|
|
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;
1816: }
1817:
1818: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
1819: {
1820: strcpy(file_handler[dst].path, file_handler[src].path);
1821: file_handler[dst].valid = 1;
1822: file_handler[dst].id = file_handler[src].id;
1823: file_handler[dst].atty = file_handler[src].atty;
1824: file_handler[dst].mode = file_handler[src].mode;
1825: file_handler[dst].info = file_handler[src].info;
1826: file_handler[dst].psp = psp_seg;
1827: }
1828:
1.1.1.20! root 1829: void msdos_file_handler_close(int fd)
1.1 root 1830: {
1831: file_handler[fd].valid = 0;
1832: }
1833:
1.1.1.14 root 1834: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 1835: {
1.1.1.14 root 1836: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
1837: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
1838: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 1839: }
1840:
1841: // find file
1842:
1843: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
1844: {
1845: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1846: return(0); // search directory only !!!
1847: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
1848: return(0);
1849: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
1850: return(0);
1851: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1852: return(0);
1853: } else if((attribute & required_mask) != required_mask) {
1854: return(0);
1855: } else {
1856: return(1);
1857: }
1858: }
1859:
1.1.1.13 root 1860: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
1861: {
1.1.1.14 root 1862: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1863: return 1;
1864: }
1865: size_t len = strlen(fd->cFileName);
1.1.1.14 root 1866: if(len > 12) {
1.1.1.13 root 1867: return 0;
1868: }
1869: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 1870: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 1871: return 0;
1872: }
1873: return 1;
1874: }
1875:
1.1 root 1876: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
1877: {
1878: FILETIME local;
1879:
1880: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
1881: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
1882: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
1883:
1884: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
1885: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
1886: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
1887:
1888: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
1889: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
1890: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
1891: }
1892:
1893: // i/o
1894:
1895: void msdos_stdio_reopen()
1896: {
1897: if(!file_handler[0].valid) {
1898: _dup2(DUP_STDIN, 0);
1899: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
1900: }
1901: if(!file_handler[1].valid) {
1902: _dup2(DUP_STDOUT, 1);
1903: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
1904: }
1905: if(!file_handler[2].valid) {
1906: _dup2(DUP_STDERR, 2);
1907: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1908: }
1909: }
1910:
1911: int msdos_kbhit()
1912: {
1913: msdos_stdio_reopen();
1914:
1.1.1.20! root 1915: process_t *process = msdos_process_info_get(current_psp);
! 1916: int fd = msdos_psp_get_file_table(0, current_psp);
! 1917:
! 1918: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 1919: // stdin is redirected to file
1.1.1.20! root 1920: return(eof(fd) == 0);
1.1 root 1921: }
1922:
1923: // check keyboard status
1.1.1.5 root 1924: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 1925: return(1);
1926: } else {
1927: return(_kbhit());
1928: }
1929: }
1930:
1931: int msdos_getch_ex(int echo)
1932: {
1933: static char prev = 0;
1934:
1935: msdos_stdio_reopen();
1936:
1.1.1.20! root 1937: process_t *process = msdos_process_info_get(current_psp);
! 1938: int fd = msdos_psp_get_file_table(0, current_psp);
! 1939:
! 1940: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 1941: // stdin is redirected to file
1942: retry:
1943: char data;
1.1.1.20! root 1944: if(_read(fd, &data, 1) == 1) {
1.1 root 1945: char tmp = data;
1946: if(data == 0x0a) {
1947: if(prev == 0x0d) {
1948: goto retry; // CRLF -> skip LF
1949: } else {
1950: data = 0x0d; // LF only -> CR
1951: }
1952: }
1953: prev = tmp;
1954: return(data);
1955: }
1956: return(EOF);
1957: }
1958:
1959: // input from console
1.1.1.5 root 1960: int key_char, key_scan;
1961: if(key_code != 0) {
1962: key_char = (key_code >> 0) & 0xff;
1963: key_scan = (key_code >> 8) & 0xff;
1964: key_code >>= 16;
1965: } else {
1.1.1.14 root 1966: while(key_buf_char->count() == 0 && !m_halted) {
1967: if(!update_key_buffer()) {
1968: Sleep(10);
1969: }
1970: }
1971: if(m_halted) {
1972: // ctrl-c pressed - insert CR to terminate input loops
1973: key_char = 0x0d;
1974: key_scan = 0;
1975: } else {
1976: key_char = key_buf_char->read();
1977: key_scan = key_buf_scan->read();
1.1.1.5 root 1978: }
1.1 root 1979: }
1980: if(echo && key_char) {
1981: msdos_putch(key_char);
1982: }
1983: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
1984: }
1985:
1986: inline int msdos_getch()
1987: {
1988: return(msdos_getch_ex(0));
1989: }
1990:
1991: inline int msdos_getche()
1992: {
1993: return(msdos_getch_ex(1));
1994: }
1995:
1996: int msdos_write(int fd, const void *buffer, unsigned int count)
1997: {
1998: static int is_cr = 0;
1999:
2000: if(fd == 1 && !file_handler[1].atty) {
2001: // CR+LF -> LF
2002: UINT8 *buf = (UINT8 *)buffer;
2003: for(unsigned int i = 0; i < count; i++) {
2004: UINT8 data = buf[i];
2005: if(is_cr) {
2006: if(data != 0x0a) {
2007: UINT8 tmp = 0x0d;
2008: _write(1, &tmp, 1);
2009: }
2010: _write(1, &data, 1);
2011: is_cr = 0;
2012: } else if(data == 0x0d) {
2013: is_cr = 1;
2014: } else {
2015: _write(1, &data, 1);
2016: }
2017: }
2018: return(count);
2019: }
1.1.1.14 root 2020: vram_flush();
1.1 root 2021: return(_write(fd, buffer, count));
2022: }
2023:
2024: void msdos_putch(UINT8 data)
2025: {
2026: static int p = 0;
2027: static int is_kanji = 0;
2028: static int is_esc = 0;
2029: static int stored_x;
2030: static int stored_y;
2031: static WORD stored_a;
1.1.1.20! root 2032: static char tmp[64], out[64];
1.1 root 2033:
2034: msdos_stdio_reopen();
2035:
1.1.1.20! root 2036: process_t *process = msdos_process_info_get(current_psp);
! 2037: int fd = msdos_psp_get_file_table(1, current_psp);
! 2038:
! 2039: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2040: // stdout is redirected to file
1.1.1.20! root 2041: msdos_write(fd, &data, 1);
1.1 root 2042: return;
2043: }
2044:
2045: // output to console
2046: tmp[p++] = data;
2047:
1.1.1.14 root 2048: vram_flush();
2049:
1.1 root 2050: if(is_kanji) {
2051: // kanji character
2052: is_kanji = 0;
2053: } else if(is_esc) {
2054: // escape sequense
2055: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2056: p = is_esc = 0;
2057: } else if(tmp[1] == '=' && p == 4) {
2058: COORD co;
2059: co.X = tmp[3] - 0x20;
1.1.1.14 root 2060: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2061: SetConsoleCursorPosition(hStdout, co);
2062: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2063: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2064: cursor_moved = false;
2065: p = is_esc = 0;
2066: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2067: CONSOLE_SCREEN_BUFFER_INFO csbi;
2068: COORD co;
2069: GetConsoleScreenBufferInfo(hStdout, &csbi);
2070: co.X = csbi.dwCursorPosition.X;
2071: co.Y = csbi.dwCursorPosition.Y;
2072: WORD wAttributes = csbi.wAttributes;
2073:
2074: if(tmp[1] == 'D') {
2075: co.Y++;
2076: } else if(tmp[1] == 'E') {
2077: co.X = 0;
2078: co.Y++;
2079: } else if(tmp[1] == 'M') {
2080: co.Y--;
2081: } else if(tmp[1] == '*') {
2082: SMALL_RECT rect;
1.1.1.14 root 2083: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2084: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2085: co.X = 0;
2086: co.Y = csbi.srWindow.Top;
1.1 root 2087: } else if(tmp[1] == '[') {
2088: int param[256], params = 0;
2089: memset(param, 0, sizeof(param));
2090: for(int i = 2; i < p; i++) {
2091: if(tmp[i] >= '0' && tmp[i] <= '9') {
2092: param[params] *= 10;
2093: param[params] += tmp[i] - '0';
2094: } else {
2095: params++;
2096: }
2097: }
2098: if(data == 'A') {
1.1.1.14 root 2099: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2100: } else if(data == 'B') {
1.1.1.14 root 2101: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2102: } else if(data == 'C') {
1.1.1.14 root 2103: co.X += (params == 0) ? 1 : param[0];
1.1 root 2104: } else if(data == 'D') {
1.1.1.14 root 2105: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2106: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2107: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2108: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2109: } else if(data == 'J') {
2110: SMALL_RECT rect;
1.1.1.14 root 2111: clear_scr_buffer(csbi.wAttributes);
1.1 root 2112: if(param[0] == 0) {
2113: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2114: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2115: if(co.Y < csbi.srWindow.Bottom) {
2116: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2117: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2118: }
2119: } else if(param[0] == 1) {
1.1.1.14 root 2120: if(co.Y > csbi.srWindow.Top) {
2121: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2122: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2123: }
2124: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2125: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2126: } else if(param[0] == 2) {
1.1.1.14 root 2127: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2128: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2129: co.X = co.Y = 0;
2130: }
2131: } else if(data == 'K') {
2132: SMALL_RECT rect;
1.1.1.14 root 2133: clear_scr_buffer(csbi.wAttributes);
1.1 root 2134: if(param[0] == 0) {
2135: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2136: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2137: } else if(param[0] == 1) {
2138: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2139: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2140: } else if(param[0] == 2) {
2141: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2142: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2143: }
2144: } else if(data == 'L') {
2145: SMALL_RECT rect;
1.1.1.14 root 2146: if(params == 0) {
2147: param[0] = 1;
1.1 root 2148: }
1.1.1.14 root 2149: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2150: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2151: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2152: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2153: clear_scr_buffer(csbi.wAttributes);
1.1 root 2154: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2155: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2156: co.X = 0;
2157: } else if(data == 'M') {
2158: SMALL_RECT rect;
1.1.1.14 root 2159: if(params == 0) {
2160: param[0] = 1;
2161: }
2162: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2163: clear_scr_buffer(csbi.wAttributes);
2164: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2165: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2166: } else {
1.1.1.14 root 2167: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2168: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2169: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2170: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2171: clear_scr_buffer(csbi.wAttributes);
1.1 root 2172: }
2173: co.X = 0;
2174: } else if(data == 'h') {
2175: if(tmp[2] == '>' && tmp[3] == '5') {
2176: CONSOLE_CURSOR_INFO cur;
2177: GetConsoleCursorInfo(hStdout, &cur);
2178: if(cur.bVisible) {
2179: cur.bVisible = FALSE;
1.1.1.14 root 2180: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2181: }
2182: }
2183: } else if(data == 'l') {
2184: if(tmp[2] == '>' && tmp[3] == '5') {
2185: CONSOLE_CURSOR_INFO cur;
2186: GetConsoleCursorInfo(hStdout, &cur);
2187: if(!cur.bVisible) {
2188: cur.bVisible = TRUE;
1.1.1.14 root 2189: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2190: }
2191: }
2192: } else if(data == 'm') {
2193: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2194: int reverse = 0, hidden = 0;
2195: for(int i = 0; i < params; i++) {
2196: if(param[i] == 1) {
2197: wAttributes |= FOREGROUND_INTENSITY;
2198: } else if(param[i] == 4) {
2199: wAttributes |= COMMON_LVB_UNDERSCORE;
2200: } else if(param[i] == 7) {
2201: reverse = 1;
2202: } else if(param[i] == 8 || param[i] == 16) {
2203: hidden = 1;
2204: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2205: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2206: if(param[i] >= 17 && param[i] <= 23) {
2207: param[i] -= 16;
2208: } else {
2209: param[i] -= 30;
2210: }
2211: if(param[i] & 1) {
2212: wAttributes |= FOREGROUND_RED;
2213: }
2214: if(param[i] & 2) {
2215: wAttributes |= FOREGROUND_GREEN;
2216: }
2217: if(param[i] & 4) {
2218: wAttributes |= FOREGROUND_BLUE;
2219: }
2220: } else if(param[i] >= 40 && param[i] <= 47) {
2221: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2222: if((param[i] - 40) & 1) {
2223: wAttributes |= BACKGROUND_RED;
2224: }
2225: if((param[i] - 40) & 2) {
2226: wAttributes |= BACKGROUND_GREEN;
2227: }
2228: if((param[i] - 40) & 4) {
2229: wAttributes |= BACKGROUND_BLUE;
2230: }
2231: }
2232: }
2233: if(reverse) {
2234: wAttributes &= ~0xff;
2235: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2236: }
2237: if(hidden) {
2238: wAttributes &= ~0x0f;
2239: wAttributes |= (wAttributes >> 4) & 0x0f;
2240: }
2241: } else if(data == 'n') {
2242: if(param[0] == 6) {
2243: char tmp[16];
2244: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2245: int len = strlen(tmp);
2246: for(int i = 0; i < len; i++) {
2247: key_buf_char->write(tmp[i]);
2248: key_buf_scan->write(0x00);
2249: }
2250: }
2251: } else if(data == 's') {
2252: stored_x = co.X;
2253: stored_y = co.Y;
2254: stored_a = wAttributes;
2255: } else if(data == 'u') {
2256: co.X = stored_x;
2257: co.Y = stored_y;
2258: wAttributes = stored_a;
2259: }
2260: }
2261: if(co.X < 0) {
2262: co.X = 0;
2263: } else if(co.X >= csbi.dwSize.X) {
2264: co.X = csbi.dwSize.X - 1;
2265: }
1.1.1.14 root 2266: if(co.Y < csbi.srWindow.Top) {
2267: co.Y = csbi.srWindow.Top;
2268: } else if(co.Y > csbi.srWindow.Bottom) {
2269: co.Y = csbi.srWindow.Bottom;
1.1 root 2270: }
2271: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2272: SetConsoleCursorPosition(hStdout, co);
2273: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2274: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2275: cursor_moved = false;
2276: }
2277: if(wAttributes != csbi.wAttributes) {
2278: SetConsoleTextAttribute(hStdout, wAttributes);
2279: }
2280: p = is_esc = 0;
2281: }
2282: return;
2283: } else {
2284: if(msdos_lead_byte_check(data)) {
2285: is_kanji = 1;
2286: return;
2287: } else if(data == 0x1b) {
2288: is_esc = 1;
2289: return;
2290: }
2291: }
1.1.1.20! root 2292:
! 2293: DWORD q = 0, num;
! 2294: is_kanji = 0;
! 2295: for(int i = 0; i < p; i++) {
! 2296: UINT8 c = tmp[i];
! 2297: if(is_kanji) {
! 2298: is_kanji = 0;
! 2299: } else if(msdos_lead_byte_check(data)) {
! 2300: is_kanji = 1;
! 2301: } else if(msdos_ctrl_code_check(data)) {
! 2302: out[q++] = '^';
! 2303: c += 'A' - 1;
! 2304: }
! 2305: out[q++] = c;
! 2306: }
! 2307: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 2308: p = 0;
1.1.1.14 root 2309:
1.1.1.15 root 2310: if(!restore_console_on_exit) {
2311: CONSOLE_SCREEN_BUFFER_INFO csbi;
2312: GetConsoleScreenBufferInfo(hStdout, &csbi);
2313: scr_top = csbi.srWindow.Top;
2314: }
1.1 root 2315: cursor_moved = true;
2316: }
2317:
2318: int msdos_aux_in()
2319: {
2320: #ifdef SUPPORT_AUX_PRN
1.1.1.20! root 2321: process_t *process = msdos_process_info_get(current_psp);
! 2322: int fd = msdos_psp_get_file_table(3, current_psp);
! 2323:
! 2324: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 2325: char data = 0;
1.1.1.20! root 2326: _read(fd, &data, 1);
1.1 root 2327: return(data);
2328: } else {
2329: return(EOF);
2330: }
2331: #else
2332: return(0);
2333: #endif
2334: }
2335:
2336: void msdos_aux_out(char data)
2337: {
2338: #ifdef SUPPORT_AUX_PRN
1.1.1.20! root 2339: process_t *process = msdos_process_info_get(current_psp);
! 2340: int fd = msdos_psp_get_file_table(3, current_psp);
! 2341:
! 2342: if(fd < process->max_files && file_handler[fd].valid) {
! 2343: msdos_write(fd, &data, 1);
1.1 root 2344: }
2345: #endif
2346: }
2347:
2348: void msdos_prn_out(char data)
2349: {
2350: #ifdef SUPPORT_AUX_PRN
1.1.1.20! root 2351: process_t *process = msdos_process_info_get(current_psp);
! 2352: int fd = msdos_psp_get_file_table(4, current_psp);
! 2353:
! 2354: if(fd < process->max_files && file_handler[fd].valid) {
! 2355: msdos_write(fd, &data, 1);
1.1 root 2356: }
2357: #endif
2358: }
2359:
2360: // memory control
2361:
1.1.1.19 root 2362: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 2363: {
2364: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2365:
2366: mcb->mz = mz;
2367: mcb->psp = psp;
1.1.1.19 root 2368: mcb->paragraphs32 = paragraphs;
1.1 root 2369: return(mcb);
2370: }
2371:
2372: void msdos_mcb_check(mcb_t *mcb)
2373: {
2374: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2375: fatalerror("broken mcb\n");
2376: }
2377: }
2378:
2379: int msdos_mem_split(int seg, int paragraphs)
2380: {
2381: int mcb_seg = seg - 1;
2382: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2383: msdos_mcb_check(mcb);
2384:
1.1.1.19 root 2385: if(mcb->paragraphs() > paragraphs) {
1.1 root 2386: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 2387: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 2388:
2389: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2390: mcb->mz = 'M';
1.1.1.19 root 2391: mcb->paragraphs32 = paragraphs;
1.1 root 2392: return(0);
2393: }
2394: return(-1);
2395: }
2396:
2397: void msdos_mem_merge(int seg)
2398: {
2399: int mcb_seg = seg - 1;
2400: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2401: msdos_mcb_check(mcb);
2402:
2403: while(1) {
2404: if(mcb->mz == 'Z') {
2405: break;
2406: }
1.1.1.19 root 2407: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 2408: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2409: msdos_mcb_check(next_mcb);
2410:
2411: if(next_mcb->psp != 0) {
2412: break;
2413: }
2414: mcb->mz = next_mcb->mz;
1.1.1.19 root 2415: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 2416: }
2417: }
2418:
1.1.1.8 root 2419: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2420: {
2421: while(1) {
2422: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2423:
1.1.1.14 root 2424: if(mcb->psp == 0) {
2425: msdos_mem_merge(mcb_seg + 1);
2426: } else {
2427: msdos_mcb_check(mcb);
2428: }
1.1.1.8 root 2429: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2430: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 2431: msdos_mem_split(mcb_seg + 1, paragraphs);
2432: mcb->psp = current_psp;
2433: return(mcb_seg + 1);
2434: }
2435: }
2436: if(mcb->mz == 'Z') {
2437: break;
2438: }
1.1.1.19 root 2439: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2440: }
2441: return(-1);
2442: }
2443:
2444: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2445: {
2446: int mcb_seg = seg - 1;
2447: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2448: msdos_mcb_check(mcb);
1.1.1.19 root 2449: int current_paragraphs = mcb->paragraphs();
1.1 root 2450:
2451: msdos_mem_merge(seg);
1.1.1.19 root 2452: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 2453: if(max_paragraphs) {
1.1.1.19 root 2454: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 2455: }
1.1 root 2456: msdos_mem_split(seg, current_paragraphs);
2457: return(-1);
2458: }
2459: msdos_mem_split(seg, paragraphs);
2460: return(0);
2461: }
2462:
2463: void msdos_mem_free(int seg)
2464: {
2465: int mcb_seg = seg - 1;
2466: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2467: msdos_mcb_check(mcb);
2468:
2469: mcb->psp = 0;
2470: msdos_mem_merge(seg);
2471: }
2472:
1.1.1.8 root 2473: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2474: {
2475: int max_paragraphs = 0;
2476:
2477: while(1) {
2478: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2479: msdos_mcb_check(mcb);
2480:
1.1.1.8 root 2481: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2482: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
2483: max_paragraphs = mcb->paragraphs();
1.1 root 2484: }
2485: }
2486: if(mcb->mz == 'Z') {
2487: break;
2488: }
1.1.1.19 root 2489: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2490: }
1.1.1.14 root 2491: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2492: }
2493:
1.1.1.8 root 2494: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2495: {
2496: int last_seg = -1;
2497:
2498: while(1) {
2499: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2500: msdos_mcb_check(mcb);
2501:
1.1.1.14 root 2502: if(mcb->psp == psp) {
1.1.1.8 root 2503: last_seg = mcb_seg;
2504: }
1.1.1.14 root 2505: if(mcb->mz == 'Z') {
2506: break;
2507: }
1.1.1.19 root 2508: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 2509: }
2510: return(last_seg);
2511: }
2512:
1.1.1.19 root 2513: int msdos_mem_get_umb_linked()
2514: {
2515: int mcb_seg = first_mcb;
2516:
2517: while(1) {
2518: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2519: msdos_mcb_check(mcb);
2520:
2521: if(mcb->mz == 'Z') {
2522: if(mcb_seg >= (UMB_TOP >> 4)) {
2523: return(-1);
2524: }
2525: break;
2526: }
2527: mcb_seg += 1 + mcb->paragraphs();
2528: }
2529: return(0);
2530: }
2531:
2532: int msdos_mem_link_umb()
2533: {
2534: int mcb_seg = first_mcb;
2535:
2536: while(1) {
2537: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2538: msdos_mcb_check(mcb);
2539: mcb_seg += 1 + mcb->paragraphs();
2540:
2541: if(mcb->mz == 'Z') {
2542: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2543: mcb->mz = 'M';
1.1.1.20! root 2544: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 2545: return(-1);
2546: }
2547: break;
2548: }
2549: }
2550: return(0);
2551: }
2552:
2553: int msdos_mem_unlink_umb()
2554: {
2555: int mcb_seg = first_mcb;
2556:
2557: while(1) {
2558: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2559: msdos_mcb_check(mcb);
2560: mcb_seg += 1 + mcb->paragraphs();
2561:
2562: if(mcb->mz == 'Z') {
2563: break;
2564: } else {
2565: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2566: mcb->mz = 'Z';
1.1.1.20! root 2567: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 2568: return(-1);
2569: }
2570: }
2571: }
2572: return(0);
2573: }
2574:
1.1 root 2575: // environment
2576:
2577: void msdos_env_set_argv(int env_seg, char *argv)
2578: {
2579: char *dst = (char *)(mem + (env_seg << 4));
2580:
2581: while(1) {
2582: if(dst[0] == 0) {
2583: break;
2584: }
2585: dst += strlen(dst) + 1;
2586: }
2587: *dst++ = 0; // end of environment
2588: *dst++ = 1; // top of argv[0]
2589: *dst++ = 0;
2590: memcpy(dst, argv, strlen(argv));
2591: dst += strlen(argv);
2592: *dst++ = 0;
2593: *dst++ = 0;
2594: }
2595:
2596: char *msdos_env_get_argv(int env_seg)
2597: {
2598: static char env[ENV_SIZE];
2599: char *src = env;
2600:
2601: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2602: while(1) {
2603: if(src[0] == 0) {
2604: if(src[1] == 1) {
2605: return(src + 3);
2606: }
2607: break;
2608: }
2609: src += strlen(src) + 1;
2610: }
2611: return(NULL);
2612: }
2613:
2614: char *msdos_env_get(int env_seg, const char *name)
2615: {
2616: static char env[ENV_SIZE];
2617: char *src = env;
2618:
2619: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2620: while(1) {
2621: if(src[0] == 0) {
2622: break;
2623: }
2624: int len = strlen(src);
2625: char *n = my_strtok(src, "=");
2626: char *v = src + strlen(n) + 1;
2627:
2628: if(_stricmp(name, n) == 0) {
2629: return(v);
2630: }
2631: src += len + 1;
2632: }
2633: return(NULL);
2634: }
2635:
2636: void msdos_env_set(int env_seg, char *name, char *value)
2637: {
2638: char env[ENV_SIZE];
2639: char *src = env;
2640: char *dst = (char *)(mem + (env_seg << 4));
2641: char *argv = msdos_env_get_argv(env_seg);
2642: int done = 0;
2643:
2644: memcpy(src, dst, ENV_SIZE);
2645: memset(dst, 0, ENV_SIZE);
2646: while(1) {
2647: if(src[0] == 0) {
2648: break;
2649: }
2650: int len = strlen(src);
2651: char *n = my_strtok(src, "=");
2652: char *v = src + strlen(n) + 1;
2653: char tmp[1024];
2654:
2655: if(_stricmp(name, n) == 0) {
2656: sprintf(tmp, "%s=%s", n, value);
2657: done = 1;
2658: } else {
2659: sprintf(tmp, "%s=%s", n, v);
2660: }
2661: memcpy(dst, tmp, strlen(tmp));
2662: dst += strlen(tmp) + 1;
2663: src += len + 1;
2664: }
2665: if(!done) {
2666: char tmp[1024];
2667:
2668: sprintf(tmp, "%s=%s", name, value);
2669: memcpy(dst, tmp, strlen(tmp));
2670: dst += strlen(tmp) + 1;
2671: }
2672: if(argv) {
2673: *dst++ = 0; // end of environment
2674: *dst++ = 1; // top of argv[0]
2675: *dst++ = 0;
2676: memcpy(dst, argv, strlen(argv));
2677: dst += strlen(argv);
2678: *dst++ = 0;
2679: *dst++ = 0;
2680: }
2681: }
2682:
2683: // process
2684:
1.1.1.8 root 2685: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 2686: {
2687: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2688:
2689: memset(psp, 0, PSP_SIZE);
2690: psp->exit[0] = 0xcd;
2691: psp->exit[1] = 0x20;
1.1.1.8 root 2692: psp->first_mcb = mcb_seg;
1.1 root 2693: psp->far_call = 0xea;
2694: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
2695: psp->cpm_entry.w.h = 0xf000;
2696: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
2697: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
2698: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
2699: psp->parent_psp = parent_psp;
1.1.1.20! root 2700: if(parent_psp == (UINT16)-1) {
! 2701: for(int i = 0; i < 20; i++) {
! 2702: if(file_handler[i].valid) {
! 2703: psp->file_table[i] = i;
! 2704: } else {
! 2705: psp->file_table[i] = 0xff;
! 2706: }
1.1 root 2707: }
1.1.1.20! root 2708: } else {
! 2709: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 2710: }
2711: psp->env_seg = env_seg;
2712: psp->stack.w.l = REG16(SP);
1.1.1.3 root 2713: psp->stack.w.h = SREG(SS);
1.1.1.14 root 2714: psp->file_table_size = 20;
2715: psp->file_table_ptr.w.l = 0x18;
2716: psp->file_table_ptr.w.h = psp_seg;
1.1 root 2717: psp->service[0] = 0xcd;
2718: psp->service[1] = 0x21;
2719: psp->service[2] = 0xcb;
2720: return(psp);
2721: }
2722:
1.1.1.20! root 2723: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
! 2724: {
! 2725: if(psp_seg && fd < 20) {
! 2726: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
! 2727: psp->file_table[fd] = value;
! 2728: }
! 2729: }
! 2730:
! 2731: int msdos_psp_get_file_table(int fd, int psp_seg)
! 2732: {
! 2733: if(psp_seg && fd < 20) {
! 2734: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
! 2735: fd = psp->file_table[fd];
! 2736: }
! 2737: return fd;
! 2738: }
! 2739:
1.1 root 2740: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
2741: {
2742: // load command file
2743: int fd = -1;
2744: int dos_command = 0;
1.1.1.4 root 2745: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name, name_tmp[MAX_PATH];
1.1 root 2746:
2747: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2748: int opt_len = mem[opt_ofs];
2749: memset(opt, 0, sizeof(opt));
2750: memcpy(opt, mem + opt_ofs + 1, opt_len);
2751:
1.1.1.14 root 2752: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
2753: // this is a batch file, run command.com
2754: char tmp[MAX_PATH];
2755: if(opt_len != 0) {
2756: sprintf(tmp, "/C %s %s", cmd, opt);
2757: } else {
2758: sprintf(tmp, "/C %s", cmd);
2759: }
2760: strcpy(opt, tmp);
2761: opt_len = strlen(opt);
2762: mem[opt_ofs] = opt_len;
2763: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2764: strcpy(command, comspec_path);
2765: strcpy(name_tmp, "COMMAND.COM");
2766: } else {
2767: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
2768: // redirect C:\COMMAND.COM to comspec_path
2769: strcpy(command, comspec_path);
2770: } else {
2771: strcpy(command, cmd);
2772: }
2773: GetFullPathName(command, MAX_PATH, path, &name);
2774: memset(name_tmp, 0, sizeof(name_tmp));
2775: strcpy(name_tmp, name);
2776:
2777: // check command.com
2778: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
2779: if(opt_len == 0) {
2780: // process_t *current_process = msdos_process_info_get(current_psp);
2781: process_t *current_process = NULL;
2782: for(int i = 0; i < MAX_PROCESS; i++) {
2783: if(process[i].psp == current_psp) {
2784: current_process = &process[i];
2785: break;
2786: }
2787: }
2788: if(current_process != NULL) {
2789: param->cmd_line.dw = current_process->dta.dw;
2790: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2791: opt_len = mem[opt_ofs];
2792: memset(opt, 0, sizeof(opt));
2793: memcpy(opt, mem + opt_ofs + 1, opt_len);
2794: }
2795: }
2796: for(int i = 0; i < opt_len; i++) {
2797: if(opt[i] == ' ') {
2798: continue;
2799: }
2800: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
2801: for(int j = i + 3; j < opt_len; j++) {
2802: if(opt[j] == ' ') {
2803: continue;
2804: }
2805: char *token = my_strtok(opt + j, " ");
2806:
2807: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
2808: // this is a batch file, okay to run command.com
2809: } else {
2810: // run program directly without command.com
2811: strcpy(command, token);
2812: char tmp[MAX_PATH];
2813: strcpy(tmp, token + strlen(token) + 1);
2814: strcpy(opt, tmp);
2815: opt_len = strlen(opt);
2816: mem[opt_ofs] = opt_len;
2817: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2818: dos_command = 1;
2819: }
2820: break;
1.1 root 2821: }
2822: }
1.1.1.14 root 2823: break;
1.1 root 2824: }
2825: }
2826: }
2827:
2828: // load command file
2829: strcpy(path, command);
2830: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2831: sprintf(path, "%s.COM", command);
2832: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2833: sprintf(path, "%s.EXE", command);
2834: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 2835: sprintf(path, "%s.BAT", command);
2836: if(_access(path, 0) == 0) {
2837: // this is a batch file, run command.com
2838: char tmp[MAX_PATH];
2839: if(opt_len != 0) {
2840: sprintf(tmp, "/C %s %s", path, opt);
2841: } else {
2842: sprintf(tmp, "/C %s", path);
2843: }
2844: strcpy(opt, tmp);
2845: opt_len = strlen(opt);
2846: mem[opt_ofs] = opt_len;
2847: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2848: strcpy(path, comspec_path);
2849: strcpy(name_tmp, "COMMAND.COM");
2850: fd = _open(path, _O_RDONLY | _O_BINARY);
2851: } else {
2852: // search path in parent environments
2853: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2854: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
2855: if(env != NULL) {
2856: char env_path[4096];
2857: strcpy(env_path, env);
2858: char *token = my_strtok(env_path, ";");
2859:
2860: while(token != NULL) {
2861: if(strlen(token) != 0) {
2862: sprintf(path, "%s", msdos_combine_path(token, command));
2863: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2864: break;
2865: }
2866: sprintf(path, "%s.COM", msdos_combine_path(token, command));
2867: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2868: break;
2869: }
2870: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
2871: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2872: break;
2873: }
2874: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
2875: if(_access(path, 0) == 0) {
2876: // this is a batch file, run command.com
2877: char tmp[MAX_PATH];
2878: if(opt_len != 0) {
2879: sprintf(tmp, "/C %s %s", path, opt);
2880: } else {
2881: sprintf(tmp, "/C %s", path);
2882: }
2883: strcpy(opt, tmp);
2884: opt_len = strlen(opt);
2885: mem[opt_ofs] = opt_len;
2886: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2887: strcpy(path, comspec_path);
2888: strcpy(name_tmp, "COMMAND.COM");
2889: fd = _open(path, _O_RDONLY | _O_BINARY);
2890: break;
2891: }
1.1.1.8 root 2892: }
1.1.1.14 root 2893: token = my_strtok(NULL, ";");
1.1 root 2894: }
2895: }
2896: }
2897: }
2898: }
2899: }
2900: if(fd == -1) {
2901: if(dos_command) {
2902: // may be dos command
2903: char tmp[MAX_PATH];
2904: sprintf(tmp, "%s %s", command, opt);
2905: system(tmp);
2906: return(0);
2907: } else {
2908: return(-1);
2909: }
2910: }
2911: _read(fd, file_buffer, sizeof(file_buffer));
2912: _close(fd);
2913:
2914: // copy environment
2915: int env_seg, psp_seg;
2916:
1.1.1.8 root 2917: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 2918: return(-1);
2919: }
2920: if(param->env_seg == 0) {
2921: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2922: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
2923: } else {
2924: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
2925: }
2926: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
2927:
2928: // check exe header
2929: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 2930: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 2931: UINT16 cs, ss, ip, sp;
2932:
2933: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
2934: // memory allocation
2935: int header_size = header->header_size * 16;
2936: int load_size = header->pages * 512 - header_size;
2937: if(header_size + load_size < 512) {
2938: load_size = 512 - header_size;
2939: }
2940: paragraphs = (PSP_SIZE + load_size) >> 4;
2941: if(paragraphs + header->min_alloc > free_paragraphs) {
2942: msdos_mem_free(env_seg);
2943: return(-1);
2944: }
2945: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
2946: if(paragraphs > free_paragraphs) {
2947: paragraphs = free_paragraphs;
2948: }
1.1.1.8 root 2949: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 2950: msdos_mem_free(env_seg);
2951: return(-1);
2952: }
2953: // relocation
2954: int start_seg = psp_seg + (PSP_SIZE >> 4);
2955: for(int i = 0; i < header->relocations; i++) {
2956: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
2957: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
2958: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
2959: }
2960: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
2961: // segments
2962: cs = header->init_cs + start_seg;
2963: ss = header->init_ss + start_seg;
2964: ip = header->init_ip;
2965: sp = header->init_sp - 2; // for symdeb
2966: } else {
2967: // memory allocation
2968: paragraphs = free_paragraphs;
1.1.1.8 root 2969: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 2970: msdos_mem_free(env_seg);
2971: return(-1);
2972: }
2973: int start_seg = psp_seg + (PSP_SIZE >> 4);
2974: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
2975: // segments
2976: cs = ss = psp_seg;
2977: ip = 0x100;
2978: sp = 0xfffe;
2979: }
2980:
2981: // create psp
1.1.1.3 root 2982: #if defined(HAS_I386)
2983: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
2984: #else
2985: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
2986: #endif
2987: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 2988: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
2989: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
2990: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
2991: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
2992:
2993: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
2994: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
2995: mcb_psp->psp = mcb_env->psp = psp_seg;
2996:
1.1.1.4 root 2997: for(int i = 0; i < 8; i++) {
2998: if(name_tmp[i] == '.') {
2999: mcb_psp->prog_name[i] = '\0';
3000: break;
3001: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3002: mcb_psp->prog_name[i] = name_tmp[i];
3003: i++;
3004: mcb_psp->prog_name[i] = name_tmp[i];
3005: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3006: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3007: } else {
3008: mcb_psp->prog_name[i] = name_tmp[i];
3009: }
3010: }
3011:
1.1 root 3012: // process info
3013: process_t *process = msdos_process_info_create(psp_seg);
3014: strcpy(process->module_dir, msdos_short_full_dir(path));
3015: process->dta.w.l = 0x80;
3016: process->dta.w.h = psp_seg;
3017: process->switchar = '/';
3018: process->max_files = 20;
3019: process->parent_int_10h_feh_called = int_10h_feh_called;
3020: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3021: process->parent_ds = SREG(DS);
1.1 root 3022:
3023: current_psp = psp_seg;
3024:
3025: if(al == 0x00) {
3026: int_10h_feh_called = int_10h_ffh_called = false;
3027:
3028: // registers and segments
3029: REG16(AX) = REG16(BX) = 0x00;
3030: REG16(CX) = 0xff;
3031: REG16(DX) = psp_seg;
3032: REG16(SI) = ip;
3033: REG16(DI) = sp;
3034: REG16(SP) = sp;
1.1.1.3 root 3035: SREG(DS) = SREG(ES) = psp_seg;
3036: SREG(SS) = ss;
3037: i386_load_segment_descriptor(DS);
3038: i386_load_segment_descriptor(ES);
3039: i386_load_segment_descriptor(SS);
1.1 root 3040:
3041: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
3042: i386_jmp_far(cs, ip);
3043: } else if(al == 0x01) {
3044: // copy ss:sp and cs:ip to param block
3045: param->sp = sp;
3046: param->ss = ss;
3047: param->ip = ip;
3048: param->cs = cs;
3049: }
3050: return(0);
3051: }
3052:
3053: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
3054: {
3055: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3056:
3057: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
3058: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
3059: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
3060:
1.1.1.3 root 3061: SREG(SS) = psp->stack.w.h;
3062: i386_load_segment_descriptor(SS);
1.1 root 3063: REG16(SP) = psp->stack.w.l;
3064: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
3065:
3066: process_t *process = msdos_process_info_get(psp_seg);
3067: int_10h_feh_called = process->parent_int_10h_feh_called;
3068: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 3069: SREG(DS) = process->parent_ds;
3070: i386_load_segment_descriptor(DS);
1.1 root 3071:
3072: if(mem_free) {
1.1.1.8 root 3073: int mcb_seg;
3074: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
3075: msdos_mem_free(mcb_seg + 1);
3076: }
3077: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
3078: msdos_mem_free(mcb_seg + 1);
3079: }
1.1 root 3080:
3081: for(int i = 0; i < MAX_FILES; i++) {
3082: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
3083: _close(i);
1.1.1.20! root 3084: msdos_file_handler_close(i);
! 3085: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 3086: }
3087: }
1.1.1.13 root 3088: msdos_dta_info_free(psp_seg);
1.1 root 3089: }
1.1.1.14 root 3090: msdos_stdio_reopen();
1.1 root 3091:
3092: memset(process, 0, sizeof(process_t));
3093:
3094: current_psp = psp->parent_psp;
3095: retval = ret;
3096: }
3097:
3098: // drive
3099:
3100: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
3101: {
3102: *seg = DPB_TOP >> 4;
3103: *ofs = sizeof(dpb_t) * drive_num;
3104: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
3105:
3106: if(!force_update && dpb->free_clusters != 0) {
3107: return(dpb->bytes_per_sector ? 1 : 0);
3108: }
3109: memset(dpb, 0, sizeof(dpb_t));
3110:
3111: int res = 0;
3112: char dev[64];
3113: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
3114:
1.1.1.17 root 3115: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 3116: if(hFile != INVALID_HANDLE_VALUE) {
3117: DISK_GEOMETRY geo;
3118: DWORD dwSize;
3119: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
3120: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
3121: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
3122: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 3123: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 3124: switch(geo.MediaType) {
3125: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
3126: dpb->media_type = 0xff;
3127: break;
3128: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
3129: dpb->media_type = 0xfe;
3130: break;
3131: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
3132: dpb->media_type = 0xfd;
3133: break;
3134: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
3135: dpb->media_type = 0xfc;
3136: break;
3137: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
3138: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
3139: dpb->media_type = 0xf9;
3140: break;
3141: case FixedMedia: // hard disk
3142: case RemovableMedia:
1.1.1.19 root 3143: case Unknown:
1.1 root 3144: dpb->media_type = 0xf8;
3145: break;
3146: default:
3147: dpb->media_type = 0xf0;
3148: break;
3149: }
3150: res = 1;
3151: }
3152: dpb->drive_num = drive_num;
3153: dpb->unit_num = drive_num;
3154: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
3155: dpb->next_dpb_seg = *seg;
1.1.1.14 root 3156: dpb->info_sector = 0xffff;
3157: dpb->backup_boot_sector = 0xffff;
1.1 root 3158: dpb->free_clusters = 0xffff;
1.1.1.14 root 3159: dpb->free_search_cluster = 0xffffffff;
1.1 root 3160: CloseHandle(hFile);
3161: }
3162: return(res);
3163: }
3164:
3165: // pc bios
3166:
1.1.1.19 root 3167: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
3168: {
3169: static unsigned __int64 start_msec_since_midnight = 0;
3170: static unsigned __int64 start_msec_since_hostboot = 0;
3171:
3172: if(start_msec_since_midnight == 0) {
3173: SYSTEMTIME time;
3174: GetLocalTime(&time);
3175: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
3176: start_msec_since_hostboot = cur_msec;
3177: }
3178: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
3179: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
3180: return (UINT32)tick;
3181: }
3182:
3183: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
3184: {
3185: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
3186: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
3187:
3188: if(prev_tick > next_tick) {
3189: mem[0x470] = 1;
3190: }
3191: *(UINT32 *)(mem + 0x46c) = next_tick;
3192: }
3193:
1.1.1.14 root 3194: inline void pcbios_irq0()
3195: {
3196: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 3197: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 3198: }
3199:
1.1.1.16 root 3200: int pcbios_get_text_vram_address(int page)
1.1 root 3201: {
3202: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3203: return TEXT_VRAM_TOP;
1.1 root 3204: } else {
1.1.1.14 root 3205: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 3206: }
3207: }
3208:
1.1.1.16 root 3209: int pcbios_get_shadow_buffer_address(int page)
1.1 root 3210: {
1.1.1.14 root 3211: if(!int_10h_feh_called) {
1.1.1.16 root 3212: return pcbios_get_text_vram_address(page);
1.1.1.14 root 3213: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3214: return SHADOW_BUF_TOP;
3215: } else {
1.1.1.14 root 3216: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 3217: }
3218: }
3219:
1.1.1.16 root 3220: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 3221: {
1.1.1.16 root 3222: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 3223: }
3224:
1.1.1.16 root 3225: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 3226: {
1.1.1.14 root 3227: // clear the existing screen, not just the new one
3228: int clr_height = max(height, scr_height);
3229:
1.1.1.16 root 3230: if(scr_width != width || scr_height != height) {
3231: change_console_size(width, height);
1.1.1.14 root 3232: }
3233: mem[0x462] = 0;
3234: *(UINT16 *)(mem + 0x44e) = 0;
3235:
1.1.1.16 root 3236: text_vram_top_address = pcbios_get_text_vram_address(0);
3237: text_vram_end_address = text_vram_top_address + width * height * 2;
3238: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
3239: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 3240:
1.1.1.16 root 3241: if(clr_screen) {
1.1.1.14 root 3242: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3243: mem[ofs++] = 0x20;
3244: mem[ofs++] = 0x07;
3245: }
3246:
3247: EnterCriticalSection(&vram_crit_sect);
3248: for(int y = 0; y < clr_height; y++) {
3249: for(int x = 0; x < scr_width; x++) {
3250: SCR_BUF(y,x).Char.AsciiChar = ' ';
3251: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3252: }
3253: }
3254: SMALL_RECT rect;
1.1.1.14 root 3255: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3256: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3257: vram_length_char = vram_last_length_char = 0;
3258: vram_length_attr = vram_last_length_attr = 0;
3259: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3260: }
1.1.1.14 root 3261: COORD co;
3262: co.X = 0;
3263: co.Y = scr_top;
3264: SetConsoleCursorPosition(hStdout, co);
3265: cursor_moved = true;
3266: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3267: }
3268:
1.1.1.16 root 3269: inline void pcbios_int_10h_00h()
3270: {
3271: switch(REG8(AL) & 0x7f) {
3272: case 0x70: // v-text mode
3273: case 0x71: // extended cga v-text mode
3274: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
3275: break;
3276: default:
3277: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
3278: break;
3279: }
3280: if(REG8(AL) & 0x80) {
3281: mem[0x487] |= 0x80;
3282: } else {
3283: mem[0x487] &= ~0x80;
3284: }
3285: mem[0x449] = REG8(AL) & 0x7f;
3286: }
3287:
1.1 root 3288: inline void pcbios_int_10h_01h()
3289: {
1.1.1.13 root 3290: mem[0x460] = REG8(CL);
3291: mem[0x461] = REG8(CH);
1.1.1.14 root 3292:
3293: CONSOLE_CURSOR_INFO ci;
3294: GetConsoleCursorInfo(hStdout, &ci);
3295: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3296: // if(ci.bVisible) {
3297: int lines = max(8, REG8(CL) + 1);
3298: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3299: // }
3300: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3301: }
3302:
3303: inline void pcbios_int_10h_02h()
3304: {
1.1.1.14 root 3305: // continuously setting the cursor effectively stops it blinking
3306: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3307: COORD co;
3308: co.X = REG8(DL);
1.1.1.14 root 3309: co.Y = REG8(DH) + scr_top;
3310:
3311: // some programs hide the cursor by moving it off screen
3312: static bool hidden = false;
3313: CONSOLE_CURSOR_INFO ci;
3314: GetConsoleCursorInfo(hStdout, &ci);
3315:
3316: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3317: if(ci.bVisible) {
3318: ci.bVisible = FALSE;
3319: // SetConsoleCursorInfo(hStdout, &ci);
3320: hidden = true;
3321: }
3322: } else if(hidden) {
3323: if(!ci.bVisible) {
3324: ci.bVisible = TRUE;
3325: // SetConsoleCursorInfo(hStdout, &ci);
3326: }
3327: hidden = false;
3328: }
1.1 root 3329: }
1.1.1.14 root 3330: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3331: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3332: }
3333:
3334: inline void pcbios_int_10h_03h()
3335: {
1.1.1.14 root 3336: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3337: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3338: REG8(CL) = mem[0x460];
3339: REG8(CH) = mem[0x461];
3340: }
3341:
3342: inline void pcbios_int_10h_05h()
3343: {
1.1.1.14 root 3344: if(REG8(AL) >= vram_pages) {
3345: return;
3346: }
3347: if(mem[0x462] != REG8(AL)) {
3348: vram_flush();
3349:
1.1 root 3350: SMALL_RECT rect;
1.1.1.14 root 3351: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3352: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3353:
1.1.1.16 root 3354: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 3355: for(int x = 0; x < scr_width; x++) {
3356: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3357: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3358: }
3359: }
1.1.1.16 root 3360: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 3361: for(int x = 0; x < scr_width; x++) {
3362: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3363: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3364: }
3365: }
1.1.1.14 root 3366: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3367:
3368: COORD co;
1.1.1.14 root 3369: co.X = mem[0x450 + REG8(AL) * 2];
3370: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3371: if(co.Y < scr_top + scr_height) {
3372: SetConsoleCursorPosition(hStdout, co);
3373: }
1.1 root 3374: }
1.1.1.14 root 3375: mem[0x462] = REG8(AL);
3376: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3377: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 3378: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 3379: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 3380: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3381: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3382: }
3383:
3384: inline void pcbios_int_10h_06h()
3385: {
1.1.1.14 root 3386: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3387: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3388: return;
3389: }
3390: vram_flush();
3391:
1.1 root 3392: SMALL_RECT rect;
1.1.1.14 root 3393: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3394: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3395:
3396: int right = min(REG8(DL), scr_width - 1);
3397: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3398:
3399: if(REG8(AL) == 0) {
1.1.1.14 root 3400: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3401: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3402: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3403: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3404: }
3405: }
3406: } else {
1.1.1.14 root 3407: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 3408: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3409: if(y2 <= bottom) {
3410: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3411: } else {
1.1.1.14 root 3412: SCR_BUF(y,x).Char.AsciiChar = ' ';
3413: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3414: }
1.1.1.14 root 3415: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3416: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3417: }
3418: }
3419: }
1.1.1.14 root 3420: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3421: }
3422:
3423: inline void pcbios_int_10h_07h()
3424: {
1.1.1.14 root 3425: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3426: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3427: return;
3428: }
3429: vram_flush();
3430:
1.1 root 3431: SMALL_RECT rect;
1.1.1.14 root 3432: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3433: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3434:
3435: int right = min(REG8(DL), scr_width - 1);
3436: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3437:
3438: if(REG8(AL) == 0) {
1.1.1.14 root 3439: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3440: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3441: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3442: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3443: }
3444: }
3445: } else {
1.1.1.14 root 3446: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 3447: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3448: if(y2 >= REG8(CH)) {
3449: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3450: } else {
1.1.1.14 root 3451: SCR_BUF(y,x).Char.AsciiChar = ' ';
3452: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3453: }
1.1.1.14 root 3454: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3455: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3456: }
3457: }
3458: }
1.1.1.14 root 3459: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3460: }
3461:
3462: inline void pcbios_int_10h_08h()
3463: {
3464: COORD co;
3465: DWORD num;
3466:
1.1.1.14 root 3467: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3468: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3469:
3470: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3471: co.Y += scr_top;
3472: vram_flush();
1.1 root 3473: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3474: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3475: REG8(AL) = scr_char[0];
3476: REG8(AH) = scr_attr[0];
3477: } else {
1.1.1.16 root 3478: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3479: }
3480: }
3481:
3482: inline void pcbios_int_10h_09h()
3483: {
3484: COORD co;
3485:
1.1.1.14 root 3486: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3487: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3488:
1.1.1.16 root 3489: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3490: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3491:
3492: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3493: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3494: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3495: while(dest < end) {
3496: write_text_vram_char(dest - vram, REG8(AL));
3497: mem[dest++] = REG8(AL);
3498: write_text_vram_attr(dest - vram, REG8(BL));
3499: mem[dest++] = REG8(BL);
1.1 root 3500: }
1.1.1.14 root 3501: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3502: } else {
1.1.1.14 root 3503: while(dest < end) {
1.1 root 3504: mem[dest++] = REG8(AL);
3505: mem[dest++] = REG8(BL);
3506: }
3507: }
3508: }
3509:
3510: inline void pcbios_int_10h_0ah()
3511: {
3512: COORD co;
3513:
1.1.1.14 root 3514: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3515: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3516:
1.1.1.16 root 3517: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3518: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3519:
3520: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3521: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3522: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3523: while(dest < end) {
3524: write_text_vram_char(dest - vram, REG8(AL));
3525: mem[dest++] = REG8(AL);
3526: dest++;
1.1 root 3527: }
1.1.1.14 root 3528: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3529: } else {
1.1.1.14 root 3530: while(dest < end) {
1.1 root 3531: mem[dest++] = REG8(AL);
3532: dest++;
3533: }
3534: }
3535: }
3536:
3537: inline void pcbios_int_10h_0eh()
3538: {
1.1.1.14 root 3539: DWORD num;
3540: COORD co;
3541:
3542: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3543: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3544:
3545: if(REG8(AL) == 7) {
3546: //MessageBeep(-1);
3547: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
3548: if(REG8(AL) == 10) {
3549: vram_flush();
3550: }
3551: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
3552: cursor_moved = true;
3553: } else {
1.1.1.16 root 3554: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 3555: if(mem[0x462] == REG8(BH)) {
3556: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3557: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3558: write_text_vram_char(dest - vram, REG8(AL));
3559: LeaveCriticalSection(&vram_crit_sect);
3560:
3561: if(++co.X == scr_width) {
3562: co.X = 0;
3563: if(++co.Y == scr_height) {
3564: vram_flush();
3565: WriteConsole(hStdout, "\n", 1, &num, NULL);
3566: cursor_moved = true;
3567: }
3568: }
3569: if(!cursor_moved) {
3570: co.Y += scr_top;
3571: SetConsoleCursorPosition(hStdout, co);
3572: cursor_moved = true;
3573: }
3574: }
3575: mem[dest] = REG8(AL);
3576: }
1.1 root 3577: }
3578:
3579: inline void pcbios_int_10h_0fh()
3580: {
3581: REG8(AL) = mem[0x449];
3582: REG8(AH) = mem[0x44a];
3583: REG8(BH) = mem[0x462];
3584: }
3585:
1.1.1.14 root 3586: inline void pcbios_int_10h_11h()
3587: {
3588: switch(REG8(AL)) {
1.1.1.16 root 3589: case 0x01:
1.1.1.14 root 3590: case 0x11:
1.1.1.16 root 3591: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 3592: break;
1.1.1.16 root 3593: case 0x02:
1.1.1.14 root 3594: case 0x12:
1.1.1.16 root 3595: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3596: break;
1.1.1.16 root 3597: case 0x04:
1.1.1.14 root 3598: case 0x14:
1.1.1.16 root 3599: pcbios_set_console_size(80, 25, true);
3600: break;
3601: case 0x18:
3602: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3603: break;
3604: case 0x30:
3605: SREG(ES) = 0;
3606: i386_load_segment_descriptor(ES);
3607: REG16(BP) = 0;
3608: REG16(CX) = mem[0x485];
3609: REG8(DL) = mem[0x484];
3610: break;
3611: }
3612: }
3613:
3614: inline void pcbios_int_10h_12h()
3615: {
1.1.1.16 root 3616: switch(REG8(BL)) {
3617: case 0x10:
1.1.1.14 root 3618: REG16(BX) = 0x0003;
3619: REG16(CX) = 0x0009;
1.1.1.16 root 3620: break;
1.1.1.14 root 3621: }
3622: }
3623:
1.1 root 3624: inline void pcbios_int_10h_13h()
3625: {
1.1.1.3 root 3626: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3627: COORD co;
3628: DWORD num;
3629:
3630: co.X = REG8(DL);
1.1.1.14 root 3631: co.Y = REG8(DH) + scr_top;
3632:
3633: vram_flush();
1.1 root 3634:
3635: switch(REG8(AL)) {
3636: case 0x00:
3637: case 0x01:
3638: if(mem[0x462] == REG8(BH)) {
3639: CONSOLE_SCREEN_BUFFER_INFO csbi;
3640: GetConsoleScreenBufferInfo(hStdout, &csbi);
3641: SetConsoleCursorPosition(hStdout, co);
3642:
3643: if(csbi.wAttributes != REG8(BL)) {
3644: SetConsoleTextAttribute(hStdout, REG8(BL));
3645: }
1.1.1.14 root 3646: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
3647:
1.1 root 3648: if(csbi.wAttributes != REG8(BL)) {
3649: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3650: }
3651: if(REG8(AL) == 0x00) {
1.1.1.15 root 3652: if(!restore_console_on_exit) {
3653: GetConsoleScreenBufferInfo(hStdout, &csbi);
3654: scr_top = csbi.srWindow.Top;
3655: }
1.1.1.14 root 3656: co.X = mem[0x450 + REG8(BH) * 2];
3657: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3658: SetConsoleCursorPosition(hStdout, co);
3659: } else {
3660: cursor_moved = true;
3661: }
3662: } else {
1.1.1.3 root 3663: m_CF = 1;
1.1 root 3664: }
3665: break;
3666: case 0x02:
3667: case 0x03:
3668: if(mem[0x462] == REG8(BH)) {
3669: CONSOLE_SCREEN_BUFFER_INFO csbi;
3670: GetConsoleScreenBufferInfo(hStdout, &csbi);
3671: SetConsoleCursorPosition(hStdout, co);
3672:
3673: WORD wAttributes = csbi.wAttributes;
3674: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
3675: if(wAttributes != mem[ofs + 1]) {
3676: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
3677: wAttributes = mem[ofs + 1];
3678: }
1.1.1.14 root 3679: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 3680: }
3681: if(csbi.wAttributes != wAttributes) {
3682: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3683: }
3684: if(REG8(AL) == 0x02) {
1.1.1.14 root 3685: co.X = mem[0x450 + REG8(BH) * 2];
3686: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3687: SetConsoleCursorPosition(hStdout, co);
3688: } else {
3689: cursor_moved = true;
3690: }
3691: } else {
1.1.1.3 root 3692: m_CF = 1;
1.1 root 3693: }
3694: break;
3695: case 0x10:
3696: case 0x11:
3697: if(mem[0x462] == REG8(BH)) {
3698: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
3699: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
3700: for(int i = 0; i < num; i++) {
3701: mem[ofs++] = scr_char[i];
3702: mem[ofs++] = scr_attr[i];
3703: if(REG8(AL) == 0x11) {
3704: mem[ofs++] = 0;
3705: mem[ofs++] = 0;
3706: }
3707: }
3708: } else {
1.1.1.16 root 3709: 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 3710: mem[ofs++] = mem[src++];
3711: mem[ofs++] = mem[src++];
3712: if(REG8(AL) == 0x11) {
3713: mem[ofs++] = 0;
3714: mem[ofs++] = 0;
3715: }
1.1.1.14 root 3716: if(++co.X == scr_width) {
3717: if(++co.Y == scr_height) {
1.1 root 3718: break;
3719: }
3720: co.X = 0;
3721: }
3722: }
3723: }
3724: break;
3725: case 0x20:
3726: case 0x21:
3727: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3728: int len = min(REG16(CX), scr_width * scr_height);
3729: for(int i = 0; i < len; i++) {
1.1 root 3730: scr_char[i] = mem[ofs++];
3731: scr_attr[i] = mem[ofs++];
3732: if(REG8(AL) == 0x21) {
3733: ofs += 2;
3734: }
3735: }
1.1.1.14 root 3736: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3737: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3738: } else {
1.1.1.16 root 3739: 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 3740: mem[dest++] = mem[ofs++];
3741: mem[dest++] = mem[ofs++];
3742: if(REG8(AL) == 0x21) {
3743: ofs += 2;
3744: }
1.1.1.14 root 3745: if(++co.X == scr_width) {
3746: if(++co.Y == scr_height) {
1.1 root 3747: break;
3748: }
3749: co.X = 0;
3750: }
3751: }
3752: }
3753: break;
3754: default:
1.1.1.3 root 3755: m_CF = 1;
1.1 root 3756: break;
3757: }
3758: }
3759:
1.1.1.14 root 3760: inline void pcbios_int_10h_1ah()
3761: {
3762: switch(REG8(AL)) {
3763: case 0x00:
3764: REG8(AL) = 0x1a;
3765: REG8(BL) = 0x08;
3766: REG8(BH) = 0x00;
3767: break;
3768: default:
3769: m_CF = 1;
3770: break;
3771: }
3772: }
3773:
1.1 root 3774: inline void pcbios_int_10h_1dh()
3775: {
3776: switch(REG8(AL)) {
3777: case 0x01:
3778: break;
3779: case 0x02:
3780: REG16(BX) = 0;
3781: break;
3782: default:
1.1.1.3 root 3783: m_CF = 1;
1.1 root 3784: break;
3785: }
3786: }
3787:
3788: inline void pcbios_int_10h_82h()
3789: {
3790: static UINT8 mode = 0;
3791:
3792: switch(REG8(AL)) {
3793: case 0:
3794: if(REG8(BL) != 0xff) {
3795: mode = REG8(BL);
3796: }
3797: REG8(AL) = mode;
3798: break;
3799: default:
1.1.1.3 root 3800: m_CF = 1;
1.1 root 3801: break;
3802: }
3803: }
3804:
3805: inline void pcbios_int_10h_feh()
3806: {
3807: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3808: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 3809: i386_load_segment_descriptor(ES);
1.1.1.8 root 3810: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 3811: }
3812: int_10h_feh_called = true;
3813: }
3814:
3815: inline void pcbios_int_10h_ffh()
3816: {
3817: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
3818: COORD co;
3819: DWORD num;
3820:
1.1.1.14 root 3821: vram_flush();
3822:
3823: co.X = (REG16(DI) >> 1) % scr_width;
3824: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 3825: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
3826: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 3827: int len;
3828: for(len = 0; ofs < end; len++) {
3829: scr_char[len] = mem[ofs++];
3830: scr_attr[len] = mem[ofs++];
3831: }
3832: co.Y += scr_top;
3833: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3834: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3835: }
3836: int_10h_ffh_called = true;
3837: }
3838:
1.1.1.14 root 3839: inline void pcbios_int_15h_10h()
3840: {
3841: if(REG8(AL) == 0) {
3842: Sleep(10);
3843: hardware_update();
3844: } else {
3845: REG8(AH) = 0x86;
3846: m_CF = 1;
3847: }
3848: }
3849:
1.1 root 3850: inline void pcbios_int_15h_23h()
3851: {
3852: switch(REG8(AL)) {
3853: case 0:
1.1.1.8 root 3854: REG8(CL) = cmos_read(0x2d);
3855: REG8(CH) = cmos_read(0x2e);
1.1 root 3856: break;
3857: case 1:
1.1.1.8 root 3858: cmos_write(0x2d, REG8(CL));
3859: cmos_write(0x2e, REG8(CH));
1.1 root 3860: break;
3861: default:
3862: REG8(AH) = 0x86;
1.1.1.3 root 3863: m_CF = 1;
1.1 root 3864: break;
3865: }
3866: }
3867:
3868: inline void pcbios_int_15h_24h()
3869: {
3870: switch(REG8(AL)) {
3871: case 0:
1.1.1.3 root 3872: i386_set_a20_line(0);
1.1 root 3873: REG8(AH) = 0;
3874: break;
3875: case 1:
1.1.1.3 root 3876: i386_set_a20_line(1);
1.1 root 3877: REG8(AH) = 0;
3878: break;
3879: case 2:
3880: REG8(AH) = 0;
1.1.1.3 root 3881: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 3882: REG16(CX) = 0;
3883: break;
3884: case 3:
3885: REG16(AX) = 0;
3886: REG16(BX) = 0;
3887: break;
3888: }
3889: }
3890:
3891: inline void pcbios_int_15h_49h()
3892: {
1.1.1.14 root 3893: REG8(AH) = 0;
3894: REG8(BL) = 0; // DOS/V
1.1 root 3895: }
3896:
3897: inline void pcbios_int_15h_86h()
3898: {
3899: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 3900: UINT32 msec = usec / 1000;
3901:
3902: while(msec) {
3903: UINT32 tmp = min(msec, 100);
3904: if(msec - tmp < 10) {
3905: tmp = msec;
3906: }
3907: Sleep(tmp);
3908:
3909: if(m_halted) {
3910: return;
3911: }
3912: msec -= tmp;
3913: }
1.1 root 3914: }
3915:
3916: inline void pcbios_int_15h_87h()
3917: {
3918: // copy extended memory (from DOSBox)
3919: int len = REG16(CX) * 2;
1.1.1.3 root 3920: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 3921: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
3922: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
3923: memcpy(mem + dst, mem + src, len);
3924: REG16(AX) = 0x00;
3925: }
3926:
3927: inline void pcbios_int_15h_88h()
3928: {
1.1.1.17 root 3929: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 3930: }
3931:
3932: inline void pcbios_int_15h_89h()
3933: {
1.1.1.3 root 3934: #if defined(HAS_I386) || defined(HAS_I286)
1.1 root 3935: // switch to protected mode (from DOSBox)
3936: write_io_byte(0x20, 0x10);
3937: write_io_byte(0x21, REG8(BH));
3938: write_io_byte(0x21, 0x00);
3939: write_io_byte(0xa0, 0x10);
3940: write_io_byte(0xa1, REG8(BL));
3941: write_io_byte(0xa1, 0x00);
1.1.1.3 root 3942: i386_set_a20_line(1);
3943: int ofs = SREG_BASE(ES) + REG16(SI);
3944: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
3945: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
3946: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
3947: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
3948: #if defined(HAS_I386)
3949: m_cr[0] |= 1;
3950: #else
3951: m_msw |= 1;
3952: #endif
3953: SREG(DS) = 0x18;
3954: SREG(ES) = 0x20;
3955: SREG(SS) = 0x28;
3956: i386_load_segment_descriptor(DS);
3957: i386_load_segment_descriptor(ES);
3958: i386_load_segment_descriptor(SS);
1.1 root 3959: REG16(SP) += 6;
1.1.1.3 root 3960: #if defined(HAS_I386)
3961: set_flags(0); // ???
3962: #else
3963: m_flags = 2;
3964: ExpandFlags(m_flags);
3965: #endif
1.1 root 3966: REG16(AX) = 0x00;
3967: i386_jmp_far(0x30, REG16(CX));
3968: #else
3969: REG8(AH) = 0x86;
1.1.1.3 root 3970: m_CF = 1;
1.1 root 3971: #endif
3972: }
3973:
1.1.1.3 root 3974: #if defined(HAS_I386)
1.1 root 3975: inline void pcbios_int_15h_c9h()
3976: {
3977: REG8(AH) = 0x00;
3978: REG8(CH) = cpu_type;
3979: REG8(CL) = cpu_step;
3980: }
1.1.1.3 root 3981: #endif
1.1 root 3982:
3983: inline void pcbios_int_15h_cah()
3984: {
3985: switch(REG8(AL)) {
3986: case 0:
3987: if(REG8(BL) > 0x3f) {
3988: REG8(AH) = 0x03;
1.1.1.3 root 3989: m_CF = 1;
1.1 root 3990: } else if(REG8(BL) < 0x0e) {
3991: REG8(AH) = 0x04;
1.1.1.3 root 3992: m_CF = 1;
1.1 root 3993: } else {
1.1.1.8 root 3994: REG8(CL) = cmos_read(REG8(BL));
1.1 root 3995: }
3996: break;
3997: case 1:
3998: if(REG8(BL) > 0x3f) {
3999: REG8(AH) = 0x03;
1.1.1.3 root 4000: m_CF = 1;
1.1 root 4001: } else if(REG8(BL) < 0x0e) {
4002: REG8(AH) = 0x04;
1.1.1.3 root 4003: m_CF = 1;
1.1 root 4004: } else {
1.1.1.8 root 4005: cmos_write(REG8(BL), REG8(CL));
1.1 root 4006: }
4007: break;
4008: default:
4009: REG8(AH) = 0x86;
1.1.1.3 root 4010: m_CF = 1;
1.1 root 4011: break;
4012: }
4013: }
4014:
1.1.1.17 root 4015: #if defined(HAS_I386)
4016: inline void pcbios_int_15h_e801h()
4017: {
4018: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
4019: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
4020: }
4021: #endif
4022:
1.1.1.16 root 4023: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 4024: {
4025: UINT32 code = 0;
4026:
4027: if(key_buf_char->count() == 0) {
1.1.1.14 root 4028: if(!update_key_buffer()) {
4029: if(clear_buffer) {
4030: Sleep(10);
4031: } else {
4032: maybe_idle();
4033: }
4034: }
1.1 root 4035: }
4036: if(!clear_buffer) {
4037: key_buf_char->store_buffer();
4038: key_buf_scan->store_buffer();
4039: }
4040: if(key_buf_char->count() != 0) {
4041: code = key_buf_char->read() | (key_buf_scan->read() << 8);
4042: }
4043: if(key_buf_char->count() != 0) {
4044: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
4045: }
4046: if(!clear_buffer) {
4047: key_buf_char->restore_buffer();
4048: key_buf_scan->restore_buffer();
4049: }
4050: return code;
4051: }
4052:
4053: inline void pcbios_int_16h_00h()
4054: {
1.1.1.14 root 4055: while(key_code == 0 && !m_halted) {
1.1.1.16 root 4056: key_code = pcbios_get_key_code(true);
1.1 root 4057: }
4058: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
4059: if(REG8(AH) == 0x10) {
4060: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
4061: } else {
4062: key_code = ((key_code >> 16) & 0xff00);
4063: }
4064: }
4065: REG16(AX) = key_code & 0xffff;
4066: key_code >>= 16;
4067: }
4068:
4069: inline void pcbios_int_16h_01h()
4070: {
1.1.1.5 root 4071: UINT32 key_code_tmp = key_code;
1.1 root 4072:
1.1.1.5 root 4073: if(key_code_tmp == 0) {
1.1.1.16 root 4074: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 4075: }
1.1.1.14 root 4076: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
4077: if(REG8(AH) == 0x11) {
4078: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
4079: } else {
4080: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 4081: }
4082: }
1.1.1.5 root 4083: if(key_code_tmp != 0) {
4084: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 4085: }
1.1.1.3 root 4086: #if defined(HAS_I386)
1.1.1.5 root 4087: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 4088: #else
1.1.1.5 root 4089: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 4090: #endif
1.1 root 4091: }
4092:
4093: inline void pcbios_int_16h_02h()
4094: {
4095: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
4096: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
4097: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
4098: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
4099: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
4100: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
4101: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
4102: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
4103: }
4104:
4105: inline void pcbios_int_16h_03h()
4106: {
4107: static UINT16 status = 0;
4108:
4109: switch(REG8(AL)) {
4110: case 0x05:
4111: status = REG16(BX);
4112: break;
4113: case 0x06:
4114: REG16(BX) = status;
4115: break;
4116: default:
1.1.1.3 root 4117: m_CF = 1;
1.1 root 4118: break;
4119: }
4120: }
4121:
4122: inline void pcbios_int_16h_05h()
4123: {
1.1.1.14 root 4124: key_buf_char->write(REG8(CL));
4125: key_buf_scan->write(REG8(CH));
1.1 root 4126: REG8(AL) = 0x00;
4127: }
4128:
4129: inline void pcbios_int_16h_12h()
4130: {
4131: pcbios_int_16h_02h();
4132:
4133: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
4134: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
4135: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
4136: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
4137: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
4138: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
4139: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
4140: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
4141: }
4142:
4143: inline void pcbios_int_16h_13h()
4144: {
4145: static UINT16 status = 0;
4146:
4147: switch(REG8(AL)) {
4148: case 0x00:
4149: status = REG16(DX);
4150: break;
4151: case 0x01:
4152: REG16(DX) = status;
4153: break;
4154: default:
1.1.1.3 root 4155: m_CF = 1;
1.1 root 4156: break;
4157: }
4158: }
4159:
4160: inline void pcbios_int_16h_14h()
4161: {
4162: static UINT8 status = 0;
4163:
4164: switch(REG8(AL)) {
4165: case 0x00:
4166: case 0x01:
4167: status = REG8(AL);
4168: break;
4169: case 0x02:
4170: REG8(AL) = status;
4171: break;
4172: default:
1.1.1.3 root 4173: m_CF = 1;
1.1 root 4174: break;
4175: }
4176: }
4177:
4178: inline void pcbios_int_1ah_00h()
4179: {
1.1.1.19 root 4180: pcbios_update_daily_timer_counter(timeGetTime());
4181: REG16(CX) = *(UINT16 *)(mem + 0x46e);
4182: REG16(DX) = *(UINT16 *)(mem + 0x46c);
4183: REG8(AL) = mem[0x470];
4184: mem[0x470] = 0;
1.1 root 4185: }
4186:
4187: inline int to_bcd(int t)
4188: {
4189: int u = (t % 100) / 10;
4190: return (u << 4) | (t % 10);
4191: }
4192:
4193: inline void pcbios_int_1ah_02h()
4194: {
4195: SYSTEMTIME time;
4196:
4197: GetLocalTime(&time);
4198: REG8(CH) = to_bcd(time.wHour);
4199: REG8(CL) = to_bcd(time.wMinute);
4200: REG8(DH) = to_bcd(time.wSecond);
4201: REG8(DL) = 0x00;
4202: }
4203:
4204: inline void pcbios_int_1ah_04h()
4205: {
4206: SYSTEMTIME time;
4207:
4208: GetLocalTime(&time);
4209: REG8(CH) = to_bcd(time.wYear / 100);
4210: REG8(CL) = to_bcd(time.wYear);
4211: REG8(DH) = to_bcd(time.wMonth);
4212: REG8(DL) = to_bcd(time.wDay);
4213: }
4214:
4215: inline void pcbios_int_1ah_0ah()
4216: {
4217: SYSTEMTIME time;
4218: FILETIME file_time;
4219: WORD dos_date, dos_time;
4220:
4221: GetLocalTime(&time);
4222: SystemTimeToFileTime(&time, &file_time);
4223: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
4224: REG16(CX) = dos_date;
4225: }
4226:
4227: // msdos system call
4228:
4229: inline void msdos_int_21h_00h()
4230: {
1.1.1.3 root 4231: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 4232: }
4233:
4234: inline void msdos_int_21h_01h()
4235: {
4236: REG8(AL) = msdos_getche();
1.1.1.8 root 4237: // some seconds may be passed in console
1.1 root 4238: hardware_update();
4239: }
4240:
4241: inline void msdos_int_21h_02h()
4242: {
4243: msdos_putch(REG8(DL));
4244: }
4245:
4246: inline void msdos_int_21h_03h()
4247: {
4248: REG8(AL) = msdos_aux_in();
4249: }
4250:
4251: inline void msdos_int_21h_04h()
4252: {
4253: msdos_aux_out(REG8(DL));
4254: }
4255:
4256: inline void msdos_int_21h_05h()
4257: {
4258: msdos_prn_out(REG8(DL));
4259: }
4260:
4261: inline void msdos_int_21h_06h()
4262: {
4263: if(REG8(DL) == 0xff) {
4264: if(msdos_kbhit()) {
4265: REG8(AL) = msdos_getch();
1.1.1.3 root 4266: #if defined(HAS_I386)
4267: m_ZF = 0;
4268: #else
4269: m_ZeroVal = 1;
4270: #endif
1.1 root 4271: } else {
4272: REG8(AL) = 0;
1.1.1.3 root 4273: #if defined(HAS_I386)
4274: m_ZF = 1;
4275: #else
4276: m_ZeroVal = 0;
4277: #endif
1.1.1.14 root 4278: maybe_idle();
1.1 root 4279: }
4280: } else {
4281: msdos_putch(REG8(DL));
4282: }
4283: }
4284:
4285: inline void msdos_int_21h_07h()
4286: {
4287: REG8(AL) = msdos_getch();
1.1.1.8 root 4288: // some seconds may be passed in console
1.1 root 4289: hardware_update();
4290: }
4291:
4292: inline void msdos_int_21h_08h()
4293: {
4294: REG8(AL) = msdos_getch();
1.1.1.8 root 4295: // some seconds may be passed in console
1.1 root 4296: hardware_update();
4297: }
4298:
4299: inline void msdos_int_21h_09h()
4300: {
1.1.1.20! root 4301: process_t *process = msdos_process_info_get(current_psp);
! 4302: int fd = msdos_psp_get_file_table(1, current_psp);
! 4303:
1.1.1.14 root 4304: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
4305: int len = 0;
1.1 root 4306:
1.1.1.14 root 4307: while(str[len] != '$' && len < 0x10000) {
4308: len++;
4309: }
1.1.1.20! root 4310: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4311: // stdout is redirected to file
1.1.1.20! root 4312: msdos_write(fd, str, len);
1.1 root 4313: } else {
4314: for(int i = 0; i < len; i++) {
1.1.1.14 root 4315: msdos_putch(str[i]);
1.1 root 4316: }
4317: }
4318: }
4319:
4320: inline void msdos_int_21h_0ah()
4321: {
1.1.1.3 root 4322: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4323: int max = mem[ofs] - 1;
4324: UINT8 *buf = mem + ofs + 2;
4325: int chr, p = 0;
4326:
4327: while((chr = msdos_getch()) != 0x0d) {
4328: if(chr == 0x00) {
4329: // skip 2nd byte
4330: msdos_getch();
4331: } else if(chr == 0x08) {
4332: // back space
4333: if(p > 0) {
4334: p--;
1.1.1.20! root 4335: if(msdos_ctrl_code_check(buf[p])) {
! 4336: msdos_putch(chr);
! 4337: msdos_putch(chr);
! 4338: msdos_putch(' ');
! 4339: msdos_putch(' ');
! 4340: msdos_putch(chr);
! 4341: msdos_putch(chr);
! 4342: } else {
! 4343: msdos_putch(chr);
! 4344: msdos_putch(' ');
! 4345: msdos_putch(chr);
! 4346: }
1.1 root 4347: }
4348: } else if(p < max) {
4349: buf[p++] = chr;
4350: msdos_putch(chr);
4351: }
4352: }
4353: buf[p] = 0x0d;
4354: mem[ofs + 1] = p;
1.1.1.8 root 4355: // some seconds may be passed in console
1.1 root 4356: hardware_update();
4357: }
4358:
4359: inline void msdos_int_21h_0bh()
4360: {
4361: if(msdos_kbhit()) {
4362: REG8(AL) = 0xff;
4363: } else {
4364: REG8(AL) = 0x00;
1.1.1.14 root 4365: maybe_idle();
1.1 root 4366: }
4367: }
4368:
4369: inline void msdos_int_21h_0ch()
4370: {
4371: // clear key buffer
1.1.1.20! root 4372: process_t *process = msdos_process_info_get(current_psp);
! 4373: int fd = msdos_psp_get_file_table(0, current_psp);
! 4374:
! 4375: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4376: // stdin is redirected to file
4377: } else {
4378: while(msdos_kbhit()) {
4379: msdos_getch();
4380: }
4381: }
4382:
4383: switch(REG8(AL)) {
4384: case 0x01:
4385: msdos_int_21h_01h();
4386: break;
4387: case 0x06:
4388: msdos_int_21h_06h();
4389: break;
4390: case 0x07:
4391: msdos_int_21h_07h();
4392: break;
4393: case 0x08:
4394: msdos_int_21h_08h();
4395: break;
4396: case 0x0a:
4397: msdos_int_21h_0ah();
4398: break;
4399: default:
4400: REG16(AX) = 0x01;
1.1.1.3 root 4401: m_CF = 1;
1.1 root 4402: break;
4403: }
4404: }
4405:
4406: inline void msdos_int_21h_0dh()
4407: {
4408: }
4409:
4410: inline void msdos_int_21h_0eh()
4411: {
4412: if(REG8(DL) < 26) {
4413: _chdrive(REG8(DL) + 1);
4414: msdos_cds_update(REG8(DL));
4415: }
4416: REG8(AL) = 26; // zdrive
4417: }
4418:
1.1.1.14 root 4419: inline void msdos_int_21h_0fh()
4420: {
4421: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4422: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4423: char *path = msdos_fcb_path(fcb);
4424: 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 4425:
1.1.1.14 root 4426: if(hFile == INVALID_HANDLE_VALUE) {
4427: REG8(AL) = 0xff;
4428: } else {
4429: REG8(AL) = 0;
4430: fcb->current_block = 0;
4431: fcb->record_size = 128;
4432: fcb->file_size = GetFileSize(hFile, NULL);
4433: fcb->handle = hFile;
4434: fcb->cur_record = 0;
4435: }
4436: }
4437:
4438: inline void msdos_int_21h_10h()
4439: {
4440: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4441: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4442:
4443: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
4444: }
4445:
1.1 root 4446: inline void msdos_int_21h_11h()
4447: {
1.1.1.3 root 4448: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4449: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4450:
4451: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4452: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4453: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4454: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4455: char *path = msdos_fcb_path(fcb);
4456: WIN32_FIND_DATA fd;
4457:
1.1.1.13 root 4458: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4459: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4460: FindClose(dtainfo->find_handle);
4461: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4462: }
4463: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 4464: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
4465: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 4466:
1.1.1.14 root 4467: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
4468: dtainfo->allowable_mask &= ~8;
1.1 root 4469: }
1.1.1.14 root 4470: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
4471: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4472: !msdos_find_file_has_8dot3name(&fd)) {
4473: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4474: FindClose(dtainfo->find_handle);
4475: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4476: break;
4477: }
4478: }
4479: }
1.1.1.13 root 4480: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4481: if(ext_fcb->flag == 0xff) {
4482: ext_find->flag = 0xff;
4483: memset(ext_find->reserved, 0, 5);
4484: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4485: }
4486: find->drive = _getdrive();
1.1.1.13 root 4487: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4488: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4489: find->nt_res = 0;
4490: msdos_find_file_conv_local_time(&fd);
4491: find->create_time_ms = 0;
4492: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4493: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4494: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4495: find->cluster_hi = find->cluster_lo = 0;
4496: find->file_size = fd.nFileSizeLow;
4497: REG8(AL) = 0x00;
1.1.1.14 root 4498: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4499: if(ext_fcb->flag == 0xff) {
4500: ext_find->flag = 0xff;
4501: memset(ext_find->reserved, 0, 5);
4502: ext_find->attribute = 8;
4503: }
4504: find->drive = _getdrive();
4505: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4506: find->attribute = 8;
4507: find->nt_res = 0;
4508: msdos_find_file_conv_local_time(&fd);
4509: find->create_time_ms = 0;
4510: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4511: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4512: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4513: find->cluster_hi = find->cluster_lo = 0;
4514: find->file_size = 0;
1.1.1.14 root 4515: dtainfo->allowable_mask &= ~8;
1.1 root 4516: REG8(AL) = 0x00;
4517: } else {
4518: REG8(AL) = 0xff;
4519: }
4520: }
4521:
4522: inline void msdos_int_21h_12h()
4523: {
1.1.1.3 root 4524: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 4525: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4526:
4527: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4528: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4529: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4530: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4531: WIN32_FIND_DATA fd;
4532:
1.1.1.13 root 4533: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4534: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4535: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 4536: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4537: !msdos_find_file_has_8dot3name(&fd)) {
4538: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4539: FindClose(dtainfo->find_handle);
4540: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4541: break;
4542: }
4543: }
4544: } else {
1.1.1.13 root 4545: FindClose(dtainfo->find_handle);
4546: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4547: }
4548: }
1.1.1.13 root 4549: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4550: if(ext_fcb->flag == 0xff) {
4551: ext_find->flag = 0xff;
4552: memset(ext_find->reserved, 0, 5);
4553: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4554: }
4555: find->drive = _getdrive();
1.1.1.13 root 4556: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4557: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4558: find->nt_res = 0;
4559: msdos_find_file_conv_local_time(&fd);
4560: find->create_time_ms = 0;
4561: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4562: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4563: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4564: find->cluster_hi = find->cluster_lo = 0;
4565: find->file_size = fd.nFileSizeLow;
4566: REG8(AL) = 0x00;
1.1.1.14 root 4567: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4568: if(ext_fcb->flag == 0xff) {
4569: ext_find->flag = 0xff;
4570: memset(ext_find->reserved, 0, 5);
4571: ext_find->attribute = 8;
4572: }
4573: find->drive = _getdrive();
4574: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4575: find->attribute = 8;
4576: find->nt_res = 0;
4577: msdos_find_file_conv_local_time(&fd);
4578: find->create_time_ms = 0;
4579: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4580: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4581: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4582: find->cluster_hi = find->cluster_lo = 0;
4583: find->file_size = 0;
1.1.1.14 root 4584: dtainfo->allowable_mask &= ~8;
1.1 root 4585: REG8(AL) = 0x00;
4586: } else {
4587: REG8(AL) = 0xff;
4588: }
4589: }
4590:
4591: inline void msdos_int_21h_13h()
4592: {
1.1.1.3 root 4593: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 4594: REG8(AL) = 0xff;
4595: } else {
4596: REG8(AL) = 0x00;
4597: }
4598: }
4599:
1.1.1.16 root 4600: inline void msdos_int_21h_14h()
4601: {
4602: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4603: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4604: process_t *process = msdos_process_info_get(current_psp);
4605: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4606: DWORD num = 0;
4607:
4608: memset(mem + dta_laddr, 0, fcb->record_size);
4609: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4610: REG8(AL) = 1;
4611: } else {
4612: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4613: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4614: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4615: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
4616: }
4617: }
4618:
4619: inline void msdos_int_21h_15h()
1.1.1.14 root 4620: {
4621: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4622: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 4623: process_t *process = msdos_process_info_get(current_psp);
4624: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4625: DWORD num = 0;
1.1.1.14 root 4626:
1.1.1.16 root 4627: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4628: REG8(AL) = 1;
4629: } else {
4630: fcb->file_size = GetFileSize(fcb->handle, NULL);
4631: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4632: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4633: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4634: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
4635: }
4636: }
4637:
4638: inline void msdos_int_21h_16h()
4639: {
4640: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4641: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 4642: char *path = msdos_fcb_path(fcb);
4643: 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 4644:
1.1.1.14 root 4645: if(hFile == INVALID_HANDLE_VALUE) {
4646: REG8(AL) = 0xff;
4647: } else {
4648: REG8(AL) = 0;
4649: fcb->current_block = 0;
4650: fcb->record_size = 128;
4651: fcb->file_size = 0;
4652: fcb->handle = hFile;
4653: fcb->cur_record = 0;
4654: }
4655: }
4656:
1.1.1.16 root 4657: inline void msdos_int_21h_17h()
4658: {
4659: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4660: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
4661: char *path_src = msdos_fcb_path(fcb_src);
4662: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
4663: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
4664: char *path_dst = msdos_fcb_path(fcb_dst);
4665:
4666: if(rename(path_src, path_dst)) {
4667: REG8(AL) = 0xff;
4668: } else {
4669: REG8(AL) = 0;
4670: }
4671: }
4672:
1.1 root 4673: inline void msdos_int_21h_18h()
4674: {
4675: REG8(AL) = 0x00;
4676: }
4677:
4678: inline void msdos_int_21h_19h()
4679: {
4680: REG8(AL) = _getdrive() - 1;
4681: }
4682:
4683: inline void msdos_int_21h_1ah()
4684: {
4685: process_t *process = msdos_process_info_get(current_psp);
4686:
4687: process->dta.w.l = REG16(DX);
1.1.1.3 root 4688: process->dta.w.h = SREG(DS);
1.1 root 4689: }
4690:
4691: inline void msdos_int_21h_1bh()
4692: {
4693: int drive_num = _getdrive() - 1;
4694: UINT16 seg, ofs;
4695:
4696: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4697: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4698: REG8(AL) = dpb->highest_sector_num + 1;
4699: REG16(CX) = dpb->bytes_per_sector;
4700: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4701: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4702: } else {
4703: REG8(AL) = 0xff;
1.1.1.3 root 4704: m_CF = 1;
1.1 root 4705: }
4706:
4707: }
4708:
4709: inline void msdos_int_21h_1ch()
4710: {
4711: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
4712: UINT16 seg, ofs;
4713:
4714: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4715: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4716: REG8(AL) = dpb->highest_sector_num + 1;
4717: REG16(CX) = dpb->bytes_per_sector;
4718: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4719: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4720: } else {
4721: REG8(AL) = 0xff;
1.1.1.3 root 4722: m_CF = 1;
1.1 root 4723: }
4724:
4725: }
4726:
4727: inline void msdos_int_21h_1dh()
4728: {
4729: REG8(AL) = 0;
4730: }
4731:
4732: inline void msdos_int_21h_1eh()
4733: {
4734: REG8(AL) = 0;
4735: }
4736:
4737: inline void msdos_int_21h_1fh()
4738: {
4739: int drive_num = _getdrive() - 1;
4740: UINT16 seg, ofs;
4741:
4742: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4743: REG8(AL) = 0;
1.1.1.3 root 4744: SREG(DS) = seg;
4745: i386_load_segment_descriptor(DS);
1.1 root 4746: REG16(BX) = ofs;
4747: } else {
4748: REG8(AL) = 0xff;
1.1.1.3 root 4749: m_CF = 1;
1.1 root 4750: }
4751: }
4752:
4753: inline void msdos_int_21h_20h()
4754: {
4755: REG8(AL) = 0;
4756: }
4757:
1.1.1.14 root 4758: inline void msdos_int_21h_21h()
4759: {
4760: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4761: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4762:
4763: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4764: REG8(AL) = 1;
4765: } else {
4766: process_t *process = msdos_process_info_get(current_psp);
4767: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4768: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 4769: DWORD num = 0;
1.1.1.14 root 4770: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4771: REG8(AL) = 1;
4772: } else {
4773: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4774: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 4775: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 4776: }
4777: }
4778: }
4779:
4780: inline void msdos_int_21h_22h()
4781: {
4782: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4783: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4784:
4785: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4786: REG8(AL) = 0xff;
4787: } else {
4788: process_t *process = msdos_process_info_get(current_psp);
4789: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 4790: DWORD num = 0;
1.1.1.14 root 4791: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
4792: fcb->file_size = GetFileSize(fcb->handle, NULL);
4793: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4794: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 4795: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 4796: }
4797: }
4798:
1.1.1.16 root 4799: inline void msdos_int_21h_23h()
4800: {
4801: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4802: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4803: char *path = msdos_fcb_path(fcb);
4804: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4805:
4806: if(hFile == INVALID_HANDLE_VALUE) {
4807: REG8(AL) = 0xff;
4808: } else {
4809: UINT32 size = GetFileSize(hFile, NULL);
4810: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
4811: REG8(AL) = 0;
4812: }
4813: }
4814:
4815: inline void msdos_int_21h_24h()
4816: {
4817: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4818: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4819:
4820: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
4821: }
4822:
1.1 root 4823: inline void msdos_int_21h_25h()
4824: {
4825: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 4826: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 4827: }
4828:
4829: inline void msdos_int_21h_26h()
4830: {
4831: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
4832:
4833: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
4834: psp->first_mcb = REG16(DX) + 16;
4835: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
4836: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
4837: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
4838: psp->parent_psp = 0;
4839: }
4840:
1.1.1.16 root 4841: inline void msdos_int_21h_27h()
4842: {
4843: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4844: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4845:
4846: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4847: REG8(AL) = 1;
4848: } else {
4849: process_t *process = msdos_process_info_get(current_psp);
4850: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4851: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
4852: DWORD num = 0;
4853: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
4854: REG8(AL) = 1;
4855: } else {
4856: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4857: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
4858: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
4859: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
4860: }
4861: }
4862: }
4863:
4864: inline void msdos_int_21h_28h()
4865: {
4866: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4867: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4868:
4869: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4870: REG8(AL) = 0xff;
4871: } else {
4872: process_t *process = msdos_process_info_get(current_psp);
4873: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4874: DWORD num = 0;
4875: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
4876: fcb->file_size = GetFileSize(fcb->handle, NULL);
4877: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4878: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
4879: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
4880: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
4881: }
4882: }
4883:
1.1 root 4884: inline void msdos_int_21h_29h()
4885: {
1.1.1.20! root 4886: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
! 4887: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 4888: UINT8 drv = 0;
4889: char sep_chars[] = ":.;,=+";
4890: char end_chars[] = "\\<>|/\"[]";
4891: char spc_chars[] = " \t";
4892:
1.1.1.20! root 4893: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
! 4894: buffer[1023] = 0;
! 4895: memset(name, 0x20, sizeof(name));
! 4896: memset(ext, 0x20, sizeof(ext));
! 4897:
1.1 root 4898: if(REG8(AL) & 1) {
1.1.1.20! root 4899: ofs += strspn((char *)(buffer + ofs), spc_chars);
! 4900: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 4901: ofs++;
4902: }
4903: }
1.1.1.20! root 4904: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 4905:
4906: if(mem[ofs + 1] == ':') {
1.1.1.20! root 4907: if(mem[ofs] >= 'a' && mem[ofs] <= 'z') {
! 4908: drv = mem[ofs] - 'a' + 1;
! 4909: ofs += 2;
! 4910: } else if(mem[ofs] >= 'A' && mem[ofs] <= 'Z') {
! 4911: drv = mem[ofs] - 'A' + 1;
1.1 root 4912: ofs += 2;
4913: }
4914: }
1.1.1.20! root 4915: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
! 4916: UINT8 c = buffer[ofs];
! 4917: if(is_kanji) {
! 4918: is_kanji = 0;
! 4919: } else if(msdos_lead_byte_check(c)) {
! 4920: is_kanji = 1;
! 4921: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 4922: break;
4923: } else if(c >= 'a' && c <= 'z') {
4924: c -= 0x20;
4925: }
4926: ofs++;
4927: name[i] = c;
4928: }
1.1.1.20! root 4929: if(buffer[ofs] == '.') {
1.1 root 4930: ofs++;
1.1.1.20! root 4931: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
! 4932: UINT8 c = buffer[ofs];
! 4933: if(is_kanji) {
! 4934: is_kanji = 0;
! 4935: } else if(msdos_lead_byte_check(c)) {
! 4936: is_kanji = 1;
! 4937: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 4938: break;
4939: } else if(c >= 'a' && c <= 'z') {
4940: c -= 0x20;
4941: }
4942: ofs++;
4943: ext[i] = c;
4944: }
4945: }
1.1.1.20! root 4946: int si = REG16(SI) + ofs;
1.1.1.3 root 4947: int ds = SREG(DS);
1.1 root 4948: while(si > 0xffff) {
4949: si -= 0x10;
4950: ds++;
4951: }
4952: REG16(SI) = si;
1.1.1.3 root 4953: SREG(DS) = ds;
4954: i386_load_segment_descriptor(DS);
1.1 root 4955:
1.1.1.3 root 4956: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20! root 4957: if(!(REG8(AL) & 2) || drv != 0) {
! 4958: fcb[0] = drv;
! 4959: }
! 4960: if(!(REG8(AL) & 4) || name[0] != 0x20) {
! 4961: memcpy(fcb + 1, name, 8);
! 4962: }
! 4963: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
! 4964: memcpy(fcb + 9, ext, 3);
! 4965: }
! 4966: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 4967: if(fcb[i] == '*') {
4968: found_star = 1;
4969: }
4970: if(found_star) {
4971: fcb[i] = '?';
4972: }
4973: }
1.1.1.20! root 4974: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 4975: if(fcb[i] == '*') {
4976: found_star = 1;
4977: }
4978: if(found_star) {
4979: fcb[i] = '?';
4980: }
4981: }
4982:
4983: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
4984: if(memchr(fcb + 1, '?', 8 + 3)) {
4985: REG8(AL) = 0x01;
1.1.1.20! root 4986: } else {
! 4987: REG8(AL) = 0x00;
1.1 root 4988: }
4989: } else {
4990: REG8(AL) = 0xff;
4991: }
4992: }
4993:
4994: inline void msdos_int_21h_2ah()
4995: {
4996: SYSTEMTIME sTime;
4997:
4998: GetLocalTime(&sTime);
4999: REG16(CX) = sTime.wYear;
5000: REG8(DH) = (UINT8)sTime.wMonth;
5001: REG8(DL) = (UINT8)sTime.wDay;
5002: REG8(AL) = (UINT8)sTime.wDayOfWeek;
5003: }
5004:
5005: inline void msdos_int_21h_2bh()
5006: {
1.1.1.14 root 5007: REG8(AL) = 0xff;
1.1 root 5008: }
5009:
5010: inline void msdos_int_21h_2ch()
5011: {
5012: SYSTEMTIME sTime;
5013:
5014: GetLocalTime(&sTime);
5015: REG8(CH) = (UINT8)sTime.wHour;
5016: REG8(CL) = (UINT8)sTime.wMinute;
5017: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 5018: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 5019: }
5020:
5021: inline void msdos_int_21h_2dh()
5022: {
5023: REG8(AL) = 0x00;
5024: }
5025:
5026: inline void msdos_int_21h_2eh()
5027: {
5028: process_t *process = msdos_process_info_get(current_psp);
5029:
5030: process->verify = REG8(AL);
5031: }
5032:
5033: inline void msdos_int_21h_2fh()
5034: {
5035: process_t *process = msdos_process_info_get(current_psp);
5036:
5037: REG16(BX) = process->dta.w.l;
1.1.1.3 root 5038: SREG(ES) = process->dta.w.h;
5039: i386_load_segment_descriptor(ES);
1.1 root 5040: }
5041:
5042: inline void msdos_int_21h_30h()
5043: {
5044: // Version Flag / OEM
5045: if(REG8(AL) == 1) {
5046: REG8(BH) = 0x00; // not in ROM
5047: } else {
5048: REG8(BH) = 0xff; // OEM = Microsoft
5049: }
1.1.1.9 root 5050: REG8(AL) = major_version; // 7
5051: REG8(AH) = minor_version; // 10
1.1 root 5052: }
5053:
5054: inline void msdos_int_21h_31h()
5055: {
1.1.1.14 root 5056: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 5057: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
5058: }
5059:
5060: inline void msdos_int_21h_32h()
5061: {
5062: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
5063: UINT16 seg, ofs;
5064:
5065: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5066: REG8(AL) = 0;
1.1.1.3 root 5067: SREG(DS) = seg;
5068: i386_load_segment_descriptor(DS);
1.1 root 5069: REG16(BX) = ofs;
5070: } else {
5071: REG8(AL) = 0xff;
1.1.1.3 root 5072: m_CF = 1;
1.1 root 5073: }
5074: }
5075:
5076: inline void msdos_int_21h_33h()
5077: {
5078: static UINT8 state = 0x00;
5079: char path[MAX_PATH];
5080:
5081: switch(REG8(AL)) {
5082: case 0x00:
5083: REG8(DL) = state;
5084: break;
5085: case 0x01:
5086: state = REG8(DL);
5087: break;
5088: case 0x05:
5089: GetSystemDirectory(path, MAX_PATH);
5090: if(path[0] >= 'a' && path[0] <= 'z') {
5091: REG8(DL) = path[0] - 'a' + 1;
5092: } else {
5093: REG8(DL) = path[0] - 'A' + 1;
5094: }
5095: break;
5096: case 0x06:
1.1.1.2 root 5097: // MS-DOS version (7.10)
1.1 root 5098: REG8(BL) = 7;
1.1.1.2 root 5099: REG8(BH) = 10;
1.1 root 5100: REG8(DL) = 0;
5101: REG8(DH) = 0x10; // in HMA
5102: break;
1.1.1.6 root 5103: case 0x07:
5104: if(REG8(DL) == 0) {
5105: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
5106: } else if(REG8(DL) == 1) {
5107: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
5108: }
5109: break;
1.1 root 5110: default:
5111: REG16(AX) = 0x01;
1.1.1.3 root 5112: m_CF = 1;
1.1 root 5113: break;
5114: }
5115: }
5116:
5117: inline void msdos_int_21h_35h()
5118: {
5119: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 5120: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
5121: i386_load_segment_descriptor(ES);
1.1 root 5122: }
5123:
5124: inline void msdos_int_21h_36h()
5125: {
5126: struct _diskfree_t df = {0};
5127:
5128: if(_getdiskfree(REG8(DL), &df) == 0) {
5129: REG16(AX) = (UINT16)df.sectors_per_cluster;
5130: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 5131: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
5132: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 5133: } else {
5134: REG16(AX) = 0xffff;
5135: }
5136: }
5137:
5138: inline void msdos_int_21h_37h()
5139: {
5140: process_t *process = msdos_process_info_get(current_psp);
5141:
5142: switch(REG8(AL)) {
5143: case 0x00:
5144: REG8(AL) = 0x00;
5145: REG8(DL) = process->switchar;
5146: break;
5147: case 0x01:
5148: REG8(AL) = 0x00;
5149: process->switchar = REG8(DL);
5150: break;
5151: default:
5152: REG16(AX) = 1;
5153: break;
5154: }
5155: }
5156:
1.1.1.19 root 5157: int get_country_info(country_info_t *ci)
1.1.1.17 root 5158: {
5159: char LCdata[80];
5160:
1.1.1.19 root 5161: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 5162: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
5163: ci->currency_dec_digits = atoi(LCdata);
5164: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
5165: ci->currency_format = *LCdata - '0';
5166: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
5167: ci->date_format = *LCdata - '0';
5168: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
5169: memcpy(&ci->currency_symbol, LCdata, 4);
5170: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
5171: *ci->date_sep = *LCdata;
5172: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
5173: *ci->dec_sep = *LCdata;
5174: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
5175: *ci->list_sep = *LCdata;
5176: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
5177: *ci->thou_sep = *LCdata;
5178: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
5179: *ci->time_sep = *LCdata;
5180: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
5181: if(strchr(LCdata, 'H') != NULL) {
5182: ci->time_format = 1;
5183: }
1.1.1.19 root 5184: ci->case_map.w.l = 0x000c;
5185: ci->case_map.w.h = 0xffff;
1.1.1.17 root 5186: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
5187: return atoi(LCdata);
5188: }
5189:
1.1.1.14 root 5190: inline void msdos_int_21h_38h()
5191: {
5192: switch(REG8(AL)) {
5193: case 0x00:
1.1.1.19 root 5194: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 5195: break;
5196: default:
5197: REG16(AX) = 2;
5198: m_CF = 1;
5199: break;
5200: }
5201: }
5202:
1.1 root 5203: inline void msdos_int_21h_39h(int lfn)
5204: {
1.1.1.3 root 5205: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5206: REG16(AX) = errno;
1.1.1.3 root 5207: m_CF = 1;
1.1 root 5208: }
5209: }
5210:
5211: inline void msdos_int_21h_3ah(int lfn)
5212: {
1.1.1.3 root 5213: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5214: REG16(AX) = errno;
1.1.1.3 root 5215: m_CF = 1;
1.1 root 5216: }
5217: }
5218:
5219: inline void msdos_int_21h_3bh(int lfn)
5220: {
1.1.1.3 root 5221: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 5222: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 5223: m_CF = 1;
1.1 root 5224: }
5225: }
5226:
5227: inline void msdos_int_21h_3ch()
5228: {
1.1.1.3 root 5229: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5230: int attr = GetFileAttributes(path);
5231: int fd = -1;
1.1.1.11 root 5232: UINT16 info;
1.1 root 5233:
1.1.1.11 root 5234: if(msdos_is_con_path(path)) {
5235: fd = _open("CON", _O_WRONLY | _O_BINARY);
5236: info = 0x80d3;
1.1.1.14 root 5237: } else if(msdos_is_nul_path(path)) {
5238: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5239: info = 0x80d3;
1.1.1.20! root 5240: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
! 5241: fd = _open("NUL", _O_WRONLY | _O_BINARY);
! 5242: info = 0x80d3;
1.1 root 5243: } else {
5244: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 5245: info = msdos_drive_number(path);
1.1 root 5246: }
5247: if(fd != -1) {
5248: if(attr == -1) {
5249: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
5250: }
5251: SetFileAttributes(path, attr);
5252: REG16(AX) = fd;
1.1.1.11 root 5253: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20! root 5254: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5255: } else {
5256: REG16(AX) = errno;
1.1.1.3 root 5257: m_CF = 1;
1.1 root 5258: }
5259: }
5260:
5261: inline void msdos_int_21h_3dh()
5262: {
1.1.1.3 root 5263: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5264: int mode = REG8(AL) & 0x03;
1.1.1.11 root 5265: int fd = -1;
5266: UINT16 info;
1.1 root 5267:
5268: if(mode < 0x03) {
1.1.1.11 root 5269: if(msdos_is_con_path(path)) {
1.1.1.13 root 5270: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5271: info = 0x80d3;
1.1.1.14 root 5272: } else if(msdos_is_nul_path(path)) {
5273: fd = msdos_open("NUL", file_mode[mode].mode);
5274: info = 0x80d3;
1.1.1.20! root 5275: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
! 5276: fd = msdos_open("NUL", file_mode[mode].mode);
! 5277: info = 0x80d3;
1.1.1.11 root 5278: } else {
1.1.1.13 root 5279: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5280: info = msdos_drive_number(path);
5281: }
1.1 root 5282: if(fd != -1) {
5283: REG16(AX) = fd;
1.1.1.11 root 5284: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20! root 5285: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5286: } else {
5287: REG16(AX) = errno;
1.1.1.3 root 5288: m_CF = 1;
1.1 root 5289: }
5290: } else {
5291: REG16(AX) = 0x0c;
1.1.1.3 root 5292: m_CF = 1;
1.1 root 5293: }
5294: }
5295:
5296: inline void msdos_int_21h_3eh()
5297: {
5298: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 5299: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5300:
1.1.1.20! root 5301: if(fd < process->max_files && file_handler[fd].valid) {
! 5302: _close(fd);
! 5303: msdos_file_handler_close(fd);
! 5304: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 5305: } else {
5306: REG16(AX) = 0x06;
1.1.1.3 root 5307: m_CF = 1;
1.1 root 5308: }
5309: }
5310:
5311: inline void msdos_int_21h_3fh()
5312: {
5313: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 5314: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5315:
1.1.1.20! root 5316: if(fd < process->max_files && file_handler[fd].valid) {
! 5317: if(file_mode[file_handler[fd].mode].in) {
! 5318: if(file_handler[fd].atty) {
1.1 root 5319: // BX is stdin or is redirected to stdin
1.1.1.3 root 5320: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 5321: int max = REG16(CX);
5322: int p = 0;
5323:
5324: while(max > p) {
5325: int chr = msdos_getch();
5326:
5327: if(chr == 0x00) {
5328: // skip 2nd byte
5329: msdos_getch();
5330: } else if(chr == 0x0d) {
5331: // carriage return
5332: buf[p++] = 0x0d;
5333: if(max > p) {
5334: buf[p++] = 0x0a;
5335: }
1.1.1.14 root 5336: msdos_putch('\n');
1.1 root 5337: break;
5338: } else if(chr == 0x08) {
5339: // back space
5340: if(p > 0) {
5341: p--;
1.1.1.20! root 5342: if(msdos_ctrl_code_check(buf[p])) {
! 5343: msdos_putch(chr);
! 5344: msdos_putch(chr);
! 5345: msdos_putch(' ');
! 5346: msdos_putch(' ');
! 5347: msdos_putch(chr);
! 5348: msdos_putch(chr);
! 5349: } else {
! 5350: msdos_putch(chr);
! 5351: msdos_putch(' ');
! 5352: msdos_putch(chr);
! 5353: }
1.1 root 5354: }
5355: } else {
5356: buf[p++] = chr;
5357: msdos_putch(chr);
5358: }
5359: }
5360: REG16(AX) = p;
1.1.1.8 root 5361: // some seconds may be passed in console
1.1 root 5362: hardware_update();
5363: } else {
1.1.1.20! root 5364: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5365: }
5366: } else {
5367: REG16(AX) = 0x05;
1.1.1.3 root 5368: m_CF = 1;
1.1 root 5369: }
5370: } else {
5371: REG16(AX) = 0x06;
1.1.1.3 root 5372: m_CF = 1;
1.1 root 5373: }
5374: }
5375:
5376: inline void msdos_int_21h_40h()
5377: {
5378: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 5379: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5380:
1.1.1.20! root 5381: if(fd < process->max_files && file_handler[fd].valid) {
! 5382: if(file_mode[file_handler[fd].mode].out) {
1.1 root 5383: if(REG16(CX)) {
1.1.1.20! root 5384: if(file_handler[fd].atty) {
1.1 root 5385: // BX is stdout/stderr or is redirected to stdout
5386: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 5387: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 5388: }
5389: REG16(AX) = REG16(CX);
5390: } else {
1.1.1.20! root 5391: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5392: }
5393: } else {
1.1.1.20! root 5394: UINT32 pos = _tell(fd);
! 5395: _lseek(fd, 0, SEEK_END);
! 5396: UINT32 size = _tell(fd);
1.1 root 5397: REG16(AX) = 0;
1.1.1.12 root 5398: if(pos < size) {
1.1.1.20! root 5399: _lseek(fd, pos, SEEK_SET);
! 5400: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 5401: } else {
5402: for(UINT32 i = size; i < pos; i++) {
5403: UINT8 tmp = 0;
1.1.1.20! root 5404: REG16(AX) += msdos_write(fd, &tmp, 1);
1.1.1.12 root 5405: }
1.1.1.20! root 5406: _lseek(fd, pos, SEEK_SET);
1.1 root 5407: }
5408: }
5409: } else {
5410: REG16(AX) = 0x05;
1.1.1.3 root 5411: m_CF = 1;
1.1 root 5412: }
5413: } else {
5414: REG16(AX) = 0x06;
1.1.1.3 root 5415: m_CF = 1;
1.1 root 5416: }
5417: }
5418:
5419: inline void msdos_int_21h_41h(int lfn)
5420: {
1.1.1.3 root 5421: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5422: REG16(AX) = errno;
1.1.1.3 root 5423: m_CF = 1;
1.1 root 5424: }
5425: }
5426:
5427: inline void msdos_int_21h_42h()
5428: {
5429: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 5430: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5431:
1.1.1.20! root 5432: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 5433: if(REG8(AL) < 0x03) {
5434: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20! root 5435: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
! 5436: UINT32 pos = _tell(fd);
1.1 root 5437: REG16(AX) = pos & 0xffff;
5438: REG16(DX) = (pos >> 16);
5439: } else {
5440: REG16(AX) = 0x01;
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_43h(int lfn)
5450: {
1.1.1.3 root 5451: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 5452: int attr;
5453:
1.1.1.14 root 5454: if(!lfn && REG8(AL) > 2) {
5455: REG16(AX) = 0x01;
5456: m_CF = 1;
5457: return;
5458: }
5459: switch(REG8(lfn ? BL : AL)) {
1.1 root 5460: case 0x00:
5461: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 5462: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
5463: } else {
5464: REG16(AX) = (UINT16)GetLastError();
5465: m_CF = 1;
5466: }
5467: break;
5468: case 0x01:
5469: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
5470: REG16(AX) = (UINT16)GetLastError();
5471: m_CF = 1;
5472: }
5473: break;
5474: case 0x02:
5475: {
5476: DWORD size = GetCompressedFileSize(path, NULL);
5477: if(size != INVALID_FILE_SIZE) {
5478: if(size != 0 && size == GetFileSize(path, NULL)) {
5479: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
5480: // this isn't correct if the file is in the NTFS MFT
5481: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
5482: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
5483: }
5484: }
5485: REG16(AX) = LOWORD(size);
5486: REG16(DX) = HIWORD(size);
5487: } else {
5488: REG16(AX) = (UINT16)GetLastError();
5489: m_CF = 1;
1.1 root 5490: }
1.1.1.14 root 5491: }
5492: break;
5493: case 0x03:
5494: case 0x05:
5495: case 0x07:
5496: {
5497: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5498: if(hFile != INVALID_HANDLE_VALUE) {
5499: FILETIME local, time;
5500: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
5501: if(REG8(BL) == 7) {
5502: ULARGE_INTEGER hund;
5503: hund.LowPart = local.dwLowDateTime;
5504: hund.HighPart = local.dwHighDateTime;
5505: hund.QuadPart += REG16(SI) * 100000;
5506: local.dwLowDateTime = hund.LowPart;
5507: local.dwHighDateTime = hund.HighPart;
5508: }
5509: LocalFileTimeToFileTime(&local, &time);
5510: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
5511: REG8(BL) == 0x05 ? &time : NULL,
5512: REG8(BL) == 0x03 ? &time : NULL)) {
5513: REG16(AX) = (UINT16)GetLastError();
5514: m_CF = 1;
5515: }
5516: CloseHandle(hFile);
5517: } else {
5518: REG16(AX) = (UINT16)GetLastError();
5519: m_CF = 1;
1.1 root 5520: }
1.1.1.14 root 5521: }
5522: break;
5523: case 0x04:
5524: case 0x06:
5525: case 0x08:
5526: {
5527: WIN32_FILE_ATTRIBUTE_DATA fad;
5528: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
5529: FILETIME *time, local;
5530: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
5531: 0x06 ? &fad.ftLastAccessTime :
5532: &fad.ftCreationTime;
5533: FileTimeToLocalFileTime(time, &local);
5534: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
5535: if(REG8(BL) == 0x08) {
5536: ULARGE_INTEGER hund;
5537: hund.LowPart = local.dwLowDateTime;
5538: hund.HighPart = local.dwHighDateTime;
5539: hund.QuadPart /= 100000;
5540: REG16(SI) = (UINT16)(hund.QuadPart % 200);
5541: }
5542: } else {
5543: REG16(AX) = (UINT16)GetLastError();
5544: m_CF = 1;
1.1 root 5545: }
1.1.1.14 root 5546: }
5547: break;
5548: default:
5549: REG16(AX) = 0x01;
5550: m_CF = 1;
5551: break;
5552: }
5553: }
5554:
5555: inline void msdos_int_21h_44h()
5556: {
1.1.1.20! root 5557: process_t *process = msdos_process_info_get(current_psp);
! 5558: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
! 5559:
1.1.1.14 root 5560: UINT32 val = DRIVE_NO_ROOT_DIR;
5561:
5562: switch(REG8(AL)) {
5563: case 0x00:
5564: case 0x01:
5565: case 0x02:
5566: case 0x03:
5567: case 0x04:
5568: case 0x05:
5569: case 0x06:
5570: case 0x07:
1.1.1.20! root 5571: if(fd >= process->max_files || !file_handler[fd].valid) {
! 5572: REG16(AX) = 0x06;
! 5573: m_CF = 1;
! 5574: return;
1.1.1.14 root 5575: }
5576: break;
5577: case 0x08:
5578: case 0x09:
5579: if(REG8(BL) >= ('Z' - 'A' + 1)) {
5580: // invalid drive number
5581: REG16(AX) = 0x0f;
5582: m_CF = 1;
5583: return;
5584: } else {
5585: if(REG8(BL) == 0) {
5586: val = GetDriveType(NULL);
5587: } else {
5588: char tmp[8];
5589: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
5590: val = GetDriveType(tmp);
5591: }
5592: if(val == DRIVE_NO_ROOT_DIR) {
5593: // no drive
5594: REG16(AX) = 0x0f;
5595: m_CF = 1;
5596: return;
1.1 root 5597: }
5598: }
5599: break;
5600: }
5601: switch(REG8(AL)) {
5602: case 0x00: // get ioctrl data
1.1.1.20! root 5603: REG16(DX) = file_handler[fd].info;
1.1 root 5604: break;
5605: case 0x01: // set ioctrl data
1.1.1.20! root 5606: file_handler[fd].info |= REG8(DL);
1.1 root 5607: break;
5608: case 0x02: // recv from character device
5609: case 0x03: // send to character device
5610: case 0x04: // recv from block device
5611: case 0x05: // send to block device
5612: REG16(AX) = 0x05;
1.1.1.3 root 5613: m_CF = 1;
1.1 root 5614: break;
5615: case 0x06: // get read status
1.1.1.20! root 5616: if(file_mode[file_handler[fd].mode].in) {
! 5617: if(file_handler[fd].atty) {
1.1.1.14 root 5618: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 5619: } else {
1.1.1.20! root 5620: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 5621: }
1.1.1.14 root 5622: } else {
5623: REG8(AL) = 0x00;
1.1 root 5624: }
5625: break;
5626: case 0x07: // get write status
1.1.1.20! root 5627: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 5628: REG8(AL) = 0xff;
5629: } else {
5630: REG8(AL) = 0x00;
1.1 root 5631: }
5632: break;
5633: case 0x08: // check removable drive
1.1.1.14 root 5634: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
5635: // removable drive
5636: REG16(AX) = 0x00;
1.1 root 5637: } else {
1.1.1.14 root 5638: // fixed drive
5639: REG16(AX) = 0x01;
1.1 root 5640: }
5641: break;
5642: case 0x09: // check remote drive
1.1.1.14 root 5643: if(val == DRIVE_REMOTE) {
5644: // remote drive
5645: REG16(DX) = 0x1000;
1.1 root 5646: } else {
1.1.1.14 root 5647: // local drive
5648: REG16(DX) = 0x00;
1.1 root 5649: }
5650: break;
5651: case 0x0b: // set retry count
5652: break;
5653: default:
5654: REG16(AX) = 0x01;
1.1.1.3 root 5655: m_CF = 1;
1.1 root 5656: break;
5657: }
5658: }
5659:
5660: inline void msdos_int_21h_45h()
5661: {
5662: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 5663: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5664:
1.1.1.20! root 5665: if(fd < process->max_files && file_handler[fd].valid) {
! 5666: int dup_fd = _dup(fd);
! 5667: if(dup_fd != -1) {
! 5668: REG16(AX) = dup_fd;
! 5669: msdos_file_handler_dup(dup_fd, fd, current_psp);
! 5670: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
! 5671: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 5672: } else {
5673: REG16(AX) = errno;
1.1.1.3 root 5674: m_CF = 1;
1.1 root 5675: }
5676: } else {
5677: REG16(AX) = 0x06;
1.1.1.3 root 5678: m_CF = 1;
1.1 root 5679: }
5680: }
5681:
5682: inline void msdos_int_21h_46h()
5683: {
5684: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 5685: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
! 5686: int dup_fd = REG16(CX);
! 5687: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 5688:
1.1.1.20! root 5689: if(REG16(BX) == REG16(CX)) {
! 5690: REG16(AX) = 0x06;
! 5691: m_CF = 1;
! 5692: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
! 5693: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
! 5694: _close(tmp_fd);
! 5695: msdos_file_handler_close(tmp_fd);
! 5696: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
! 5697: }
! 5698: if(_dup2(fd, dup_fd) != -1) {
! 5699: msdos_file_handler_dup(dup_fd, fd, current_psp);
! 5700: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
! 5701: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 5702: } else {
5703: REG16(AX) = errno;
1.1.1.3 root 5704: m_CF = 1;
1.1 root 5705: }
5706: } else {
5707: REG16(AX) = 0x06;
1.1.1.3 root 5708: m_CF = 1;
1.1 root 5709: }
5710: }
5711:
5712: inline void msdos_int_21h_47h(int lfn)
5713: {
5714: char path[MAX_PATH];
5715:
5716: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
5717: if(path[1] == ':') {
5718: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 5719: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 5720: } else {
1.1.1.3 root 5721: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 5722: }
5723: } else {
5724: REG16(AX) = errno;
1.1.1.3 root 5725: m_CF = 1;
1.1 root 5726: }
5727: }
5728:
5729: inline void msdos_int_21h_48h()
5730: {
1.1.1.19 root 5731: int seg, umb_linked;
1.1 root 5732:
1.1.1.8 root 5733: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 5734: // unlink umb not to allocate memory in umb
5735: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
5736: msdos_mem_unlink_umb();
5737: }
1.1.1.8 root 5738: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5739: REG16(AX) = seg;
5740: } else {
5741: REG16(AX) = 0x08;
5742: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
5743: m_CF = 1;
5744: }
1.1.1.19 root 5745: if(umb_linked != 0) {
5746: msdos_mem_link_umb();
5747: }
1.1.1.8 root 5748: } else if((malloc_strategy & 0xf0) == 0x40) {
5749: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5750: REG16(AX) = seg;
5751: } else {
5752: REG16(AX) = 0x08;
5753: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
5754: m_CF = 1;
5755: }
5756: } else if((malloc_strategy & 0xf0) == 0x80) {
5757: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5758: REG16(AX) = seg;
5759: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5760: REG16(AX) = seg;
5761: } else {
5762: REG16(AX) = 0x08;
5763: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
5764: m_CF = 1;
5765: }
1.1 root 5766: }
5767: }
5768:
5769: inline void msdos_int_21h_49h()
5770: {
1.1.1.14 root 5771: int mcb_seg = SREG(ES) - 1;
5772: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5773:
5774: if(mcb->mz == 'M' || mcb->mz == 'Z') {
5775: msdos_mem_free(SREG(ES));
5776: } else {
5777: REG16(AX) = 9;
5778: m_CF = 1;
5779: }
1.1 root 5780: }
5781:
5782: inline void msdos_int_21h_4ah()
5783: {
1.1.1.14 root 5784: int mcb_seg = SREG(ES) - 1;
5785: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 5786: int max_paragraphs;
5787:
1.1.1.14 root 5788: if(mcb->mz == 'M' || mcb->mz == 'Z') {
5789: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
5790: REG16(AX) = 0x08;
5791: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
5792: m_CF = 1;
5793: }
5794: } else {
5795: REG16(AX) = 7;
1.1.1.3 root 5796: m_CF = 1;
1.1 root 5797: }
5798: }
5799:
5800: inline void msdos_int_21h_4bh()
5801: {
1.1.1.3 root 5802: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
5803: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 5804:
5805: switch(REG8(AL)) {
5806: case 0x00:
5807: case 0x01:
5808: if(msdos_process_exec(command, param, REG8(AL))) {
5809: REG16(AX) = 0x02;
1.1.1.3 root 5810: m_CF = 1;
1.1 root 5811: }
5812: break;
1.1.1.14 root 5813: case 0x03:
5814: {
5815: int fd;
5816: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
5817: REG16(AX) = 0x02;
5818: m_CF = 1;
5819: break;
5820: }
5821: int size = _read(fd, file_buffer, sizeof(file_buffer));
5822: _close(fd);
5823:
5824: UINT16 *overlay = (UINT16 *)param;
5825:
5826: // check exe header
5827: exe_header_t *header = (exe_header_t *)file_buffer;
5828: int header_size = 0;
5829: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
5830: header_size = header->header_size * 16;
5831: // relocation
5832: int start_seg = overlay[1];
5833: for(int i = 0; i < header->relocations; i++) {
5834: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
5835: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
5836: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
5837: }
5838: }
5839: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
5840: }
5841: break;
1.1 root 5842: default:
5843: REG16(AX) = 0x01;
1.1.1.3 root 5844: m_CF = 1;
1.1 root 5845: break;
5846: }
5847: }
5848:
5849: inline void msdos_int_21h_4ch()
5850: {
5851: msdos_process_terminate(current_psp, REG8(AL), 1);
5852: }
5853:
5854: inline void msdos_int_21h_4dh()
5855: {
5856: REG16(AX) = retval;
5857: }
5858:
5859: inline void msdos_int_21h_4eh()
5860: {
5861: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5862: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5863: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 5864: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5865: WIN32_FIND_DATA fd;
5866:
1.1.1.14 root 5867: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
5868: find->find_magic = FIND_MAGIC;
5869: find->dta_index = dtainfo - dtalist;
1.1 root 5870: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 5871: dtainfo->allowable_mask = REG8(CL);
5872: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 5873:
1.1.1.14 root 5874: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
5875: dtainfo->allowable_mask &= ~8;
1.1 root 5876: }
1.1.1.14 root 5877: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
5878: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5879: !msdos_find_file_has_8dot3name(&fd)) {
5880: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5881: FindClose(dtainfo->find_handle);
5882: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5883: break;
5884: }
5885: }
5886: }
1.1.1.13 root 5887: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5888: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
5889: msdos_find_file_conv_local_time(&fd);
5890: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
5891: find->size = fd.nFileSizeLow;
1.1.1.13 root 5892: strcpy(find->name, msdos_short_name(&fd));
1.1 root 5893: REG16(AX) = 0;
1.1.1.14 root 5894: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5895: find->attrib = 8;
5896: find->size = 0;
5897: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 5898: dtainfo->allowable_mask &= ~8;
1.1 root 5899: REG16(AX) = 0;
5900: } else {
5901: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 5902: m_CF = 1;
1.1 root 5903: }
5904: }
5905:
5906: inline void msdos_int_21h_4fh()
5907: {
5908: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5909: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5910: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 5911: WIN32_FIND_DATA fd;
5912:
1.1.1.14 root 5913: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
5914: REG16(AX) = 0x12;
5915: m_CF = 1;
5916: return;
5917: }
5918: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 5919: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5920: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 5921: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5922: !msdos_find_file_has_8dot3name(&fd)) {
5923: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5924: FindClose(dtainfo->find_handle);
5925: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5926: break;
5927: }
5928: }
5929: } else {
1.1.1.13 root 5930: FindClose(dtainfo->find_handle);
5931: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5932: }
5933: }
1.1.1.13 root 5934: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5935: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
5936: msdos_find_file_conv_local_time(&fd);
5937: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
5938: find->size = fd.nFileSizeLow;
1.1.1.13 root 5939: strcpy(find->name, msdos_short_name(&fd));
1.1 root 5940: REG16(AX) = 0;
1.1.1.14 root 5941: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5942: find->attrib = 8;
5943: find->size = 0;
5944: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 5945: dtainfo->allowable_mask &= ~8;
1.1 root 5946: REG16(AX) = 0;
5947: } else {
5948: REG16(AX) = 0x12;
1.1.1.3 root 5949: m_CF = 1;
1.1 root 5950: }
5951: }
5952:
5953: inline void msdos_int_21h_50h()
5954: {
1.1.1.8 root 5955: if(current_psp != REG16(BX)) {
5956: process_t *process = msdos_process_info_get(current_psp);
5957: if(process != NULL) {
5958: process->psp = REG16(BX);
5959: }
5960: current_psp = REG16(BX);
5961: }
1.1 root 5962: }
5963:
5964: inline void msdos_int_21h_51h()
5965: {
5966: REG16(BX) = current_psp;
5967: }
5968:
5969: inline void msdos_int_21h_52h()
5970: {
1.1.1.3 root 5971: SREG(ES) = (DOS_INFO_BASE >> 4);
5972: i386_load_segment_descriptor(ES);
1.1 root 5973: REG16(BX) = (DOS_INFO_BASE & 0x0f);
5974: }
5975:
5976: inline void msdos_int_21h_54h()
5977: {
5978: process_t *process = msdos_process_info_get(current_psp);
5979:
5980: REG8(AL) = process->verify;
5981: }
5982:
5983: inline void msdos_int_21h_55h()
5984: {
5985: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5986:
5987: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5988: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5989: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5990: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5991: psp->parent_psp = current_psp;
5992: }
5993:
5994: inline void msdos_int_21h_56h(int lfn)
5995: {
5996: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 5997: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
5998: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 5999:
6000: if(rename(src, dst)) {
6001: REG16(AX) = errno;
1.1.1.3 root 6002: m_CF = 1;
1.1 root 6003: }
6004: }
6005:
6006: inline void msdos_int_21h_57h()
6007: {
6008: FILETIME time, local;
1.1.1.14 root 6009: FILETIME *ctime, *atime, *mtime;
1.1.1.6 root 6010: HANDLE handle;
1.1 root 6011:
1.1.1.14 root 6012: if((handle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
6013: REG16(AX) = (UINT16)GetLastError();
6014: m_CF = 1;
6015: return;
6016: }
6017: ctime = atime = mtime = NULL;
6018:
1.1 root 6019: switch(REG8(AL)) {
6020: case 0x00:
1.1.1.6 root 6021: case 0x01:
1.1.1.14 root 6022: mtime = &time;
1.1.1.6 root 6023: break;
6024: case 0x04:
6025: case 0x05:
1.1.1.14 root 6026: atime = &time;
1.1 root 6027: break;
1.1.1.6 root 6028: case 0x06:
6029: case 0x07:
1.1.1.14 root 6030: ctime = &time;
6031: break;
6032: default:
6033: REG16(AX) = 0x01;
6034: m_CF = 1;
6035: return;
6036: }
6037: if(REG8(AL) & 1) {
1.1 root 6038: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
6039: LocalFileTimeToFileTime(&local, &time);
1.1.1.14 root 6040: if(!SetFileTime(handle, ctime, atime, mtime)) {
1.1 root 6041: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6042: m_CF = 1;
1.1 root 6043: }
1.1.1.14 root 6044: } else {
6045: if(!GetFileTime(handle, ctime, atime, mtime)) {
6046: // assume a device and use the current time
6047: GetSystemTimeAsFileTime(&time);
6048: }
6049: FileTimeToLocalFileTime(&time, &local);
6050: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 6051: }
6052: }
6053:
6054: inline void msdos_int_21h_58h()
6055: {
6056: switch(REG8(AL)) {
6057: case 0x00:
1.1.1.7 root 6058: REG16(AX) = malloc_strategy;
6059: break;
6060: case 0x01:
6061: switch(REG16(BX)) {
6062: case 0x0000:
6063: case 0x0001:
6064: case 0x0002:
6065: case 0x0040:
6066: case 0x0041:
6067: case 0x0042:
6068: case 0x0080:
6069: case 0x0081:
6070: case 0x0082:
6071: malloc_strategy = REG16(BX);
6072: break;
6073: default:
6074: REG16(AX) = 0x01;
6075: m_CF = 1;
6076: break;
6077: }
6078: break;
6079: case 0x02:
1.1.1.19 root 6080: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 6081: break;
6082: case 0x03:
6083: switch(REG16(BX)) {
6084: case 0x0000:
1.1.1.19 root 6085: msdos_mem_unlink_umb();
6086: break;
1.1.1.7 root 6087: case 0x0001:
1.1.1.19 root 6088: msdos_mem_link_umb();
1.1.1.7 root 6089: break;
6090: default:
6091: REG16(AX) = 0x01;
6092: m_CF = 1;
6093: break;
6094: }
1.1 root 6095: break;
6096: default:
6097: REG16(AX) = 0x01;
1.1.1.3 root 6098: m_CF = 1;
1.1 root 6099: break;
6100: }
6101: }
6102:
6103: inline void msdos_int_21h_59h()
6104: {
6105: REG16(AX) = error_code;
6106: switch(error_code) {
6107: case 4: // Too many open files
6108: case 8: // Insufficient memory
6109: REG8(BH) = 1; // Out of resource
6110: break;
6111: case 5: // Access denied
6112: REG8(BH) = 3; // Authorization
6113: break;
6114: case 7: // Memory control block destroyed
6115: REG8(BH) = 4; // Internal
6116: break;
6117: case 2: // File not found
6118: case 3: // Path not found
6119: case 15: // Invaid drive specified
6120: case 18: // No more files
6121: REG8(BH) = 8; // Not found
6122: break;
6123: case 32: // Sharing violation
6124: case 33: // Lock violation
6125: REG8(BH) = 10; // Locked
6126: break;
6127: // case 16: // Removal of current directory attempted
6128: case 19: // Attempted write on protected disk
6129: case 21: // Drive not ready
6130: // case 29: // Write failure
6131: // case 30: // Read failure
6132: // case 82: // Cannot create subdirectory
6133: REG8(BH) = 11; // Media
6134: break;
6135: case 80: // File already exists
6136: REG8(BH) = 12; // Already exist
6137: break;
6138: default:
6139: REG8(BH) = 13; // Unknown
6140: break;
6141: }
6142: REG8(BL) = 1; // Retry
6143: REG8(CH) = 1; // Unknown
6144: }
6145:
6146: inline void msdos_int_21h_5ah()
6147: {
1.1.1.3 root 6148: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6149: int len = strlen(path);
6150: char tmp[MAX_PATH];
6151:
6152: if(GetTempFileName(path, "TMP", 0, tmp)) {
6153: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6154:
6155: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6156: REG16(AX) = fd;
6157: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20! root 6158: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6159:
6160: strcpy(path, tmp);
6161: int dx = REG16(DX) + len;
1.1.1.3 root 6162: int ds = SREG(DS);
1.1 root 6163: while(dx > 0xffff) {
6164: dx -= 0x10;
6165: ds++;
6166: }
6167: REG16(DX) = dx;
1.1.1.3 root 6168: SREG(DS) = ds;
6169: i386_load_segment_descriptor(DS);
1.1 root 6170: } else {
6171: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6172: m_CF = 1;
1.1 root 6173: }
6174: }
6175:
6176: inline void msdos_int_21h_5bh()
6177: {
1.1.1.3 root 6178: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6179:
6180: if(_access(path, 0) == 0) {
6181: // already exists
6182: REG16(AX) = 0x50;
1.1.1.3 root 6183: m_CF = 1;
1.1 root 6184: } else {
6185: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6186:
6187: if(fd != -1) {
6188: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6189: REG16(AX) = fd;
6190: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20! root 6191: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6192: } else {
6193: REG16(AX) = errno;
1.1.1.3 root 6194: m_CF = 1;
1.1 root 6195: }
6196: }
6197: }
6198:
6199: inline void msdos_int_21h_5ch()
6200: {
6201: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 6202: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6203:
1.1.1.20! root 6204: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6205: if(REG8(AL) == 0 || REG8(AL) == 1) {
6206: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20! root 6207: UINT32 pos = _tell(fd);
! 6208: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
! 6209: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 6210: REG16(AX) = errno;
1.1.1.3 root 6211: m_CF = 1;
1.1 root 6212: }
1.1.1.20! root 6213: _lseek(fd, pos, SEEK_SET);
1.1 root 6214: // some seconds may be passed in _locking()
6215: hardware_update();
6216: } else {
6217: REG16(AX) = 0x01;
1.1.1.3 root 6218: m_CF = 1;
1.1 root 6219: }
6220: } else {
6221: REG16(AX) = 0x06;
1.1.1.3 root 6222: m_CF = 1;
1.1 root 6223: }
6224: }
6225:
6226: inline void msdos_int_21h_60h(int lfn)
6227: {
1.1.1.14 root 6228: char full[MAX_PATH], *path;
6229:
1.1 root 6230: if(lfn) {
1.1.1.14 root 6231: char *name;
6232: *full = '\0';
1.1.1.3 root 6233: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 6234: switch(REG8(CL)) {
6235: case 1:
6236: GetShortPathName(full, full, MAX_PATH);
6237: my_strupr(full);
6238: break;
6239: case 2:
6240: GetLongPathName(full, full, MAX_PATH);
6241: break;
6242: }
6243: path = full;
6244: } else {
6245: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
6246: }
6247: if(*path != '\0') {
6248: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 6249: } else {
1.1.1.14 root 6250: REG16(AX) = (UINT16)GetLastError();
6251: m_CF = 1;
1.1 root 6252: }
6253: }
6254:
6255: inline void msdos_int_21h_61h()
6256: {
6257: REG8(AL) = 0;
6258: }
6259:
6260: inline void msdos_int_21h_62h()
6261: {
6262: REG16(BX) = current_psp;
6263: }
6264:
6265: inline void msdos_int_21h_63h()
6266: {
6267: switch(REG8(AL)) {
6268: case 0x00:
1.1.1.3 root 6269: SREG(DS) = (DBCS_TABLE >> 4);
6270: i386_load_segment_descriptor(DS);
1.1 root 6271: REG16(SI) = (DBCS_TABLE & 0x0f);
6272: REG8(AL) = 0x00;
6273: break;
6274: default:
6275: REG16(AX) = 0x01;
1.1.1.3 root 6276: m_CF = 1;
1.1 root 6277: break;
6278: }
6279: }
6280:
6281: inline void msdos_int_21h_65h()
6282: {
6283: char tmp[0x10000];
6284:
6285: switch(REG8(AL)) {
1.1.1.17 root 6286: case 0x01:
6287: if(REG16(CX) >= 5) {
1.1.1.19 root 6288: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 6289: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
6290: REG16(CX) = sizeof(data);
6291: ZeroMemory(data, sizeof(data));
6292: data[0] = 0x01;
6293: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 6294: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 6295: *(UINT16 *)(data + 5) = active_code_page;
6296: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
6297: REG16(AX) = active_code_page;
6298: } else {
6299: REG16(AX) = 1;
6300: m_CF = 1;
6301: }
6302: break;
6303: case 0x02:
6304: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
6305: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
6306: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
6307: REG16(AX) = active_code_page;
6308: REG16(CX) = 0x05;
6309: break;
6310: case 0x04:
6311: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
6312: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
6313: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
6314: REG16(AX) = active_code_page;
6315: REG16(CX) = 0x05;
6316: break;
6317: case 0x05:
6318: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
6319: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
6320: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
6321: REG16(AX) = active_code_page;
6322: REG16(CX) = 0x05;
6323: break;
6324: case 0x06:
6325: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
6326: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
6327: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
6328: REG16(AX) = active_code_page;
6329: REG16(CX) = 0x05;
6330: break;
1.1 root 6331: case 0x07:
1.1.1.3 root 6332: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
6333: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
6334: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.17 root 6335: REG16(AX) = active_code_page;
1.1 root 6336: REG16(CX) = 0x05;
6337: break;
6338: case 0x20:
1.1.1.19 root 6339: memset(tmp, 0, sizeof(tmp));
6340: tmp[0] = REG8(DL);
1.1 root 6341: my_strupr(tmp);
6342: REG8(DL) = tmp[0];
6343: break;
6344: case 0x21:
6345: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 6346: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6347: my_strupr(tmp);
1.1.1.3 root 6348: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 6349: break;
6350: case 0x22:
1.1.1.3 root 6351: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 6352: break;
6353: default:
6354: REG16(AX) = 0x01;
1.1.1.3 root 6355: m_CF = 1;
1.1 root 6356: break;
6357: }
6358: }
6359:
6360: inline void msdos_int_21h_66h()
6361: {
6362: switch(REG8(AL)) {
6363: case 0x01:
6364: REG16(BX) = active_code_page;
6365: REG16(DX) = system_code_page;
6366: break;
6367: case 0x02:
6368: if(active_code_page == REG16(BX)) {
6369: REG16(AX) = 0xeb41;
6370: } else if(_setmbcp(REG16(BX)) == 0) {
6371: active_code_page = REG16(BX);
1.1.1.17 root 6372: msdos_nls_tables_update();
1.1 root 6373: REG16(AX) = 0xeb41;
6374: } else {
6375: REG16(AX) = 0x25;
1.1.1.3 root 6376: m_CF = 1;
1.1 root 6377: }
6378: break;
6379: default:
6380: REG16(AX) = 0x01;
1.1.1.3 root 6381: m_CF = 1;
1.1 root 6382: break;
6383: }
6384: }
6385:
6386: inline void msdos_int_21h_67h()
6387: {
6388: process_t *process = msdos_process_info_get(current_psp);
6389:
6390: if(REG16(BX) <= MAX_FILES) {
6391: process->max_files = max(REG16(BX), 20);
6392: } else {
6393: REG16(AX) = 0x08;
1.1.1.3 root 6394: m_CF = 1;
1.1 root 6395: }
6396: }
6397:
6398: inline void msdos_int_21h_68h()
6399: {
6400: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 6401: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6402:
1.1.1.20! root 6403: if(fd < process->max_files && file_handler[fd].valid) {
! 6404: // fflush(_fdopen(fd, ""));
1.1 root 6405: } else {
6406: REG16(AX) = 0x06;
1.1.1.3 root 6407: m_CF = 1;
1.1 root 6408: }
6409: }
6410:
6411: inline void msdos_int_21h_69h()
6412: {
1.1.1.3 root 6413: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6414: char path[] = "A:\\";
6415: char volume_label[MAX_PATH];
6416: DWORD serial_number = 0;
6417: char file_system[MAX_PATH];
6418:
6419: if(REG8(BL) == 0) {
6420: path[0] = 'A' + _getdrive() - 1;
6421: } else {
6422: path[0] = 'A' + REG8(BL) - 1;
6423: }
6424:
6425: switch(REG8(AL)) {
6426: case 0x00:
6427: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
6428: info->info_level = 0;
6429: info->serial_number = serial_number;
6430: memset(info->volume_label, 0x20, 11);
6431: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
6432: memset(info->file_system, 0x20, 8);
6433: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
6434: } else {
6435: REG16(AX) = errno;
1.1.1.3 root 6436: m_CF = 1;
1.1 root 6437: }
6438: break;
6439: case 0x01:
6440: REG16(AX) = 0x03;
1.1.1.3 root 6441: m_CF = 1;
1.1 root 6442: }
6443: }
6444:
6445: inline void msdos_int_21h_6ah()
6446: {
6447: REG8(AH) = 0x68;
6448: msdos_int_21h_68h();
6449: }
6450:
6451: inline void msdos_int_21h_6bh()
6452: {
6453: REG8(AL) = 0;
6454: }
6455:
6456: inline void msdos_int_21h_6ch(int lfn)
6457: {
1.1.1.3 root 6458: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 6459: int mode = REG8(BL) & 0x03;
6460:
6461: if(mode < 0x03) {
1.1.1.20! root 6462: if(_access(path, 0) == 0 || strncmp(path, "EMMXXXX0", 8) == 0) {
1.1 root 6463: // file exists
6464: if(REG8(DL) & 1) {
1.1.1.11 root 6465: int fd = -1;
6466: UINT16 info;
1.1 root 6467:
1.1.1.11 root 6468: if(msdos_is_con_path(path)) {
1.1.1.13 root 6469: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 6470: info = 0x80d3;
1.1.1.14 root 6471: } else if(msdos_is_nul_path(path)) {
6472: fd = msdos_open("NUL", file_mode[mode].mode);
6473: info = 0x80d3;
1.1.1.20! root 6474: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
! 6475: fd = msdos_open("NUL", file_mode[mode].mode);
! 6476: info = 0x80d3;
1.1.1.11 root 6477: } else {
1.1.1.13 root 6478: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 6479: info = msdos_drive_number(path);
6480: }
1.1 root 6481: if(fd != -1) {
6482: REG16(AX) = fd;
6483: REG16(CX) = 1;
1.1.1.11 root 6484: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20! root 6485: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6486: } else {
6487: REG16(AX) = errno;
1.1.1.3 root 6488: m_CF = 1;
1.1 root 6489: }
6490: } else if(REG8(DL) & 2) {
6491: int attr = GetFileAttributes(path);
6492: int fd = -1;
1.1.1.11 root 6493: UINT16 info;
1.1 root 6494:
1.1.1.11 root 6495: if(msdos_is_con_path(path)) {
1.1.1.13 root 6496: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 6497: info = 0x80d3;
1.1.1.14 root 6498: } else if(msdos_is_nul_path(path)) {
6499: fd = msdos_open("NUL", file_mode[mode].mode);
6500: info = 0x80d3;
1.1.1.20! root 6501: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
! 6502: fd = msdos_open("NUL", file_mode[mode].mode);
! 6503: info = 0x80d3;
1.1 root 6504: } else {
6505: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 6506: info = msdos_drive_number(path);
1.1 root 6507: }
6508: if(fd != -1) {
6509: if(attr == -1) {
6510: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
6511: }
6512: SetFileAttributes(path, attr);
6513: REG16(AX) = fd;
6514: REG16(CX) = 3;
1.1.1.11 root 6515: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20! root 6516: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6517: } else {
6518: REG16(AX) = errno;
1.1.1.3 root 6519: m_CF = 1;
1.1 root 6520: }
6521: } else {
6522: REG16(AX) = 0x50;
1.1.1.3 root 6523: m_CF = 1;
1.1 root 6524: }
6525: } else {
6526: // file not exists
6527: if(REG8(DL) & 0x10) {
6528: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6529:
6530: if(fd != -1) {
6531: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6532: REG16(AX) = fd;
6533: REG16(CX) = 2;
6534: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20! root 6535: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6536: } else {
6537: REG16(AX) = errno;
1.1.1.3 root 6538: m_CF = 1;
1.1 root 6539: }
6540: } else {
6541: REG16(AX) = 0x02;
1.1.1.3 root 6542: m_CF = 1;
1.1 root 6543: }
6544: }
6545: } else {
6546: REG16(AX) = 0x0c;
1.1.1.3 root 6547: m_CF = 1;
1.1 root 6548: }
6549: }
6550:
6551: inline void msdos_int_21h_710dh()
6552: {
6553: // reset drive
6554: }
6555:
1.1.1.17 root 6556: inline void msdos_int_21h_7141h(int lfn)
6557: {
6558: if(REG16(SI) == 0) {
6559: msdos_int_21h_41h(lfn);
6560: return;
6561: }
6562: if(REG16(SI) != 1) {
6563: REG16(AX) = 5;
6564: m_CF = 1;
6565: }
6566: /* wild card and matching attributes... */
6567: char tmp[MAX_PATH * 2];
6568: // copy search pathname (and quick check overrun)
6569: ZeroMemory(tmp, sizeof(tmp));
6570: tmp[MAX_PATH - 1] = '\0';
6571: tmp[MAX_PATH] = 1;
6572: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
6573:
6574: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
6575: REG16(AX) = 1;
6576: m_CF = 1;
6577: return;
6578: }
6579: for(char *s = tmp; *s; ++s) {
6580: if(*s == '/') {
6581: *s = '\\';
6582: }
6583: }
6584: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
6585: if(tmp_name) {
6586: ++tmp_name;
6587: } else {
6588: tmp_name = strchr(tmp, ':');
6589: tmp_name = tmp_name ? tmp_name + 1 : tmp;
6590: }
6591:
6592: WIN32_FIND_DATAA fd;
6593: HANDLE fh = FindFirstFileA(tmp, &fd);
6594: if(fh == INVALID_HANDLE_VALUE) {
6595: REG16(AX) = 2;
6596: m_CF = 1;
6597: return;
6598: }
6599: do {
6600: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
6601: strcpy(tmp_name, fd.cFileName);
6602: if(remove(msdos_trimmed_path(tmp, lfn))) {
6603: REG16(AX) = 5;
6604: m_CF = 1;
6605: break;
6606: }
6607: }
6608: } while(FindNextFileA(fh, &fd));
6609: if(!m_CF) {
6610: if(GetLastError() != ERROR_NO_MORE_FILES) {
6611: m_CF = 1;
6612: REG16(AX) = 2;
6613: }
6614: }
6615: FindClose(fh);
6616: }
6617:
1.1 root 6618: inline void msdos_int_21h_714eh()
6619: {
6620: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6621: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
6622: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6623: WIN32_FIND_DATA fd;
6624:
1.1.1.13 root 6625: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6626: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6627: FindClose(dtainfo->find_handle);
6628: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6629: }
6630: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6631: dtainfo->allowable_mask = REG8(CL);
6632: dtainfo->required_mask = REG8(CH);
6633: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6634:
1.1.1.14 root 6635: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6636: dtainfo->allowable_mask &= ~8;
1.1 root 6637: }
1.1.1.14 root 6638: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6639: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6640: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6641: FindClose(dtainfo->find_handle);
6642: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6643: break;
6644: }
6645: }
6646: }
1.1.1.13 root 6647: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6648: find->attrib = fd.dwFileAttributes;
6649: msdos_find_file_conv_local_time(&fd);
6650: if(REG16(SI) == 0) {
6651: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6652: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6653: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6654: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6655: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6656: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6657: } else {
6658: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6659: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6660: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6661: }
6662: find->size_hi = fd.nFileSizeHigh;
6663: find->size_lo = fd.nFileSizeLow;
6664: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6665: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 6666: REG16(AX) = dtainfo - dtalist + 1;
6667: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6668: // volume label
6669: find->attrib = 8;
6670: find->size_hi = find->size_lo = 0;
6671: strcpy(find->full_name, process->volume_label);
6672: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6673: dtainfo->allowable_mask &= ~8;
6674: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 6675: } else {
6676: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6677: m_CF = 1;
1.1 root 6678: }
6679: }
6680:
6681: inline void msdos_int_21h_714fh()
6682: {
6683: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6684: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6685: WIN32_FIND_DATA fd;
6686:
1.1.1.14 root 6687: if(REG16(BX) - 1u >= MAX_DTAINFO) {
6688: REG16(AX) = 6;
1.1.1.13 root 6689: m_CF = 1;
6690: return;
6691: }
1.1.1.14 root 6692: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6693: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6694: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6695: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6696: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6697: FindClose(dtainfo->find_handle);
6698: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6699: break;
6700: }
6701: }
6702: } else {
1.1.1.13 root 6703: FindClose(dtainfo->find_handle);
6704: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6705: }
6706: }
1.1.1.13 root 6707: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6708: find->attrib = fd.dwFileAttributes;
6709: msdos_find_file_conv_local_time(&fd);
6710: if(REG16(SI) == 0) {
6711: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6712: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6713: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6714: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6715: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6716: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6717: } else {
6718: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6719: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6720: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6721: }
6722: find->size_hi = fd.nFileSizeHigh;
6723: find->size_lo = fd.nFileSizeLow;
6724: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6725: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 6726: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6727: // volume label
6728: find->attrib = 8;
6729: find->size_hi = find->size_lo = 0;
6730: strcpy(find->full_name, process->volume_label);
6731: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6732: dtainfo->allowable_mask &= ~8;
1.1 root 6733: } else {
6734: REG16(AX) = 0x12;
1.1.1.3 root 6735: m_CF = 1;
1.1 root 6736: }
6737: }
6738:
6739: inline void msdos_int_21h_71a0h()
6740: {
6741: DWORD max_component_len, file_sys_flag;
6742:
1.1.1.14 root 6743: 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))) {
6744: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
6745: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 6746: REG16(CX) = (UINT16)max_component_len; // 255
6747: REG16(DX) = (UINT16)max_component_len + 5; // 260
6748: } else {
6749: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6750: m_CF = 1;
1.1 root 6751: }
6752: }
6753:
6754: inline void msdos_int_21h_71a1h()
6755: {
1.1.1.14 root 6756: if(REG16(BX) - 1u >= MAX_DTAINFO) {
6757: REG16(AX) = 6;
1.1.1.13 root 6758: m_CF = 1;
6759: return;
6760: }
1.1.1.14 root 6761: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6762: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6763: FindClose(dtainfo->find_handle);
6764: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6765: }
6766: }
6767:
6768: inline void msdos_int_21h_71a6h()
6769: {
6770: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20! root 6771: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
! 6772:
1.1.1.3 root 6773: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6774: struct _stat64 status;
6775: DWORD serial_number = 0;
6776:
1.1.1.20! root 6777: if(fd < process->max_files && file_handler[fd].valid) {
! 6778: if(_fstat64(fd, &status) == 0) {
! 6779: if(file_handler[fd].path[1] == ':') {
1.1 root 6780: // NOTE: we need to consider the network file path "\\host\share\"
6781: char volume[] = "A:\\";
1.1.1.20! root 6782: volume[0] = file_handler[fd].path[1];
1.1 root 6783: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
6784: }
1.1.1.20! root 6785: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 6786: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
6787: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
6788: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
6789: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
6790: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
6791: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
6792: *(UINT32 *)(buffer + 0x1c) = serial_number;
6793: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
6794: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
6795: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 6796: // this is dummy id and it will be changed when it is reopened...
1.1 root 6797: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20! root 6798: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 6799: } else {
6800: REG16(AX) = errno;
1.1.1.3 root 6801: m_CF = 1;
1.1 root 6802: }
6803: } else {
6804: REG16(AX) = 0x06;
1.1.1.3 root 6805: m_CF = 1;
1.1 root 6806: }
6807: }
6808:
6809: inline void msdos_int_21h_71a7h()
6810: {
6811: switch(REG8(BL)) {
6812: case 0x00:
1.1.1.3 root 6813: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 6814: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6815: m_CF = 1;
1.1 root 6816: }
6817: break;
6818: case 0x01:
6819: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 6820: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 6821: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6822: m_CF = 1;
1.1 root 6823: }
6824: break;
6825: default:
6826: REG16(AX) = 0x01;
1.1.1.3 root 6827: m_CF = 1;
1.1 root 6828: break;
6829: }
6830: }
6831:
6832: inline void msdos_int_21h_71a8h()
6833: {
6834: if(REG8(DH) == 0) {
6835: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 6836: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6837: memset(fcb, 0x20, sizeof(fcb));
6838: int len = strlen(tmp);
6839: int pos = 0;
6840: for(int i = 0; i < len; i++) {
6841: if(tmp[i] == '.') {
6842: pos = 8;
6843: } else {
6844: if(msdos_lead_byte_check(tmp[i])) {
6845: fcb[pos++] = tmp[i++];
6846: }
6847: fcb[pos++] = tmp[i];
6848: }
6849: }
1.1.1.3 root 6850: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 6851: } else {
1.1.1.3 root 6852: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6853: }
6854: }
6855:
1.1.1.14 root 6856: inline void msdos_int_21h_7300h()
6857: {
6858: if(REG8(AL) == 0) {
6859: REG8(AL) = REG8(CL);
6860: REG8(AH) = 0;
6861: } else {
6862: REG16(AX) = 0x01;
6863: m_CF = 1;
6864: }
6865: }
6866:
6867: inline void msdos_int_21h_7302h()
6868: {
6869: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
6870: UINT16 seg, ofs;
6871:
6872: if(REG16(CX) < 0x3f) {
6873: REG8(AL) = 0x18;
6874: m_CF = 1;
6875: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6876: REG8(AL) = 0xff;
6877: m_CF = 1;
6878: } else {
6879: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
6880: }
6881: }
6882:
1.1 root 6883: inline void msdos_int_21h_7303h()
6884: {
1.1.1.3 root 6885: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6886: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6887: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
6888:
6889: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
6890: info->size_of_structure = sizeof(ext_space_info_t);
6891: info->structure_version = 0;
6892: info->sectors_per_cluster = sectors_per_cluster;
6893: info->bytes_per_sector = bytes_per_sector;
6894: info->available_clusters_on_drive = free_clusters;
6895: info->total_clusters_on_drive = total_clusters;
6896: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
6897: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
6898: info->available_allocation_units = free_clusters; // ???
6899: info->total_allocation_units = total_clusters; // ???
6900: } else {
6901: REG16(AX) = errno;
1.1.1.3 root 6902: m_CF = 1;
1.1 root 6903: }
6904: }
6905:
6906: inline void msdos_int_25h()
6907: {
6908: UINT16 seg, ofs;
6909: DWORD dwSize;
6910:
1.1.1.3 root 6911: #if defined(HAS_I386)
6912: I386OP(pushf)();
6913: #else
6914: PREFIX86(_pushf());
6915: #endif
1.1 root 6916:
6917: if(!(REG8(AL) < 26)) {
6918: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 6919: m_CF = 1;
1.1 root 6920: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
6921: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6922: m_CF = 1;
1.1 root 6923: } else {
6924: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6925: char dev[64];
6926: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
6927:
6928: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
6929: if(hFile == INVALID_HANDLE_VALUE) {
6930: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6931: m_CF = 1;
1.1 root 6932: } else {
1.1.1.19 root 6933: UINT32 top_sector = REG16(DX);
6934: UINT16 sector_num = REG16(CX);
6935: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
6936:
6937: if(sector_num == 0xffff) {
6938: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
6939: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
6940: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
6941: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
6942: buffer_addr = (seg << 4) + ofs;
6943: }
6944: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
6945: // REG8(AL) = 0x02; // drive not ready
6946: // m_CF = 1;
6947: // } else
6948: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 6949: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 6950: m_CF = 1;
1.1.1.19 root 6951: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 6952: REG8(AL) = 0x0b; // read error
1.1.1.3 root 6953: m_CF = 1;
1.1 root 6954: }
6955: CloseHandle(hFile);
6956: }
6957: }
6958: }
6959:
6960: inline void msdos_int_26h()
6961: {
6962: // this operation may cause serious damage for drives, so always returns error...
6963: UINT16 seg, ofs;
6964: DWORD dwSize;
6965:
1.1.1.3 root 6966: #if defined(HAS_I386)
6967: I386OP(pushf)();
6968: #else
6969: PREFIX86(_pushf());
6970: #endif
1.1 root 6971:
6972: if(!(REG8(AL) < 26)) {
6973: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 6974: m_CF = 1;
1.1 root 6975: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
6976: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6977: m_CF = 1;
1.1 root 6978: } else {
6979: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6980: char dev[64];
6981: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
6982:
6983: if(dpb->media_type == 0xf8) {
6984: // this drive is not a floppy
1.1.1.6 root 6985: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
6986: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
6987: // }
1.1 root 6988: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6989: m_CF = 1;
1.1 root 6990: } else {
6991: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
6992: if(hFile == INVALID_HANDLE_VALUE) {
6993: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6994: m_CF = 1;
1.1 root 6995: } else {
1.1.1.19 root 6996: UINT32 top_sector = REG16(DX);
6997: UINT16 sector_num = REG16(CX);
6998: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
6999:
7000: if(sector_num == 0xffff) {
7001: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7002: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7003: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7004: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7005: buffer_addr = (seg << 4) + ofs;
7006: }
1.1 root 7007: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7008: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7009: m_CF = 1;
1.1.1.19 root 7010: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7011: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7012: m_CF = 1;
1.1.1.19 root 7013: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7014: REG8(AL) = 0x0a; // write error
1.1.1.3 root 7015: m_CF = 1;
1.1 root 7016: }
7017: CloseHandle(hFile);
7018: }
7019: }
7020: }
7021: }
7022:
7023: inline void msdos_int_27h()
7024: {
1.1.1.14 root 7025: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 7026: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 7027:
7028: // int_21h_4bh succeeded
7029: m_CF = 0;
1.1 root 7030: }
7031:
7032: inline void msdos_int_29h()
7033: {
1.1.1.14 root 7034: #if 1
7035: // need to check escape sequences
1.1 root 7036: msdos_putch(REG8(AL));
1.1.1.14 root 7037: #else
7038: DWORD num;
7039:
7040: vram_flush();
7041: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
7042: cursor_moved = true;
7043: #endif
1.1 root 7044: }
7045:
7046: inline void msdos_int_2eh()
7047: {
7048: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
7049: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7050: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 7051: char *token = my_strtok(tmp, " ");
7052: strcpy(command, token);
7053: strcpy(opt, token + strlen(token) + 1);
7054:
7055: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7056: param->env_seg = 0;
7057: param->cmd_line.w.l = 44;
7058: param->cmd_line.w.h = (WORK_TOP >> 4);
7059: param->fcb1.w.l = 24;
7060: param->fcb1.w.h = (WORK_TOP >> 4);
7061: param->fcb2.w.l = 24;
7062: param->fcb2.w.h = (WORK_TOP >> 4);
7063:
7064: memset(mem + WORK_TOP + 24, 0x20, 20);
7065:
7066: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
7067: cmd_line->len = strlen(opt);
7068: strcpy(cmd_line->cmd, opt);
7069: cmd_line->cmd[cmd_line->len] = 0x0d;
7070:
7071: msdos_process_exec(command, param, 0);
7072: REG8(AL) = 0;
7073: }
7074:
7075: inline void msdos_int_2fh_16h()
7076: {
7077: switch(REG8(AL)) {
7078: case 0x00:
1.1.1.14 root 7079: if(no_windows) {
7080: REG8(AL) = 0;
7081: } else {
1.1 root 7082: OSVERSIONINFO osvi;
7083: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
7084: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
7085: GetVersionEx(&osvi);
7086: REG8(AL) = osvi.dwMajorVersion;
7087: REG8(AH) = osvi.dwMinorVersion;
7088: }
7089: break;
1.1.1.14 root 7090: case 0x80:
7091: Sleep(10);
7092: hardware_update();
7093: REG8(AL) = 0;
7094: break;
1.1.1.20! root 7095: case 0x8f:
! 7096: switch(REG8(DH)) {
! 7097: case 0x00:
! 7098: case 0x02:
! 7099: case 0x03:
! 7100: REG16(AX) = 0x00;
! 7101: break;
! 7102: case 0x01:
! 7103: REG16(AX) = 0x168f;
! 7104: break;
! 7105: }
! 7106: break;
1.1 root 7107: default:
7108: REG16(AX) = 0x01;
1.1.1.3 root 7109: m_CF = 1;
1.1 root 7110: break;
7111: }
7112: }
7113:
7114: inline void msdos_int_2fh_1ah()
7115: {
7116: switch(REG8(AL)) {
7117: case 0x00:
7118: // ansi.sys is installed
7119: REG8(AL) = 0xff;
7120: break;
7121: default:
7122: REG16(AX) = 0x01;
1.1.1.3 root 7123: m_CF = 1;
1.1 root 7124: break;
7125: }
7126: }
7127:
7128: inline void msdos_int_2fh_43h()
7129: {
7130: switch(REG8(AL)) {
7131: case 0x00:
1.1.1.19 root 7132: // xms is installed ?
7133: #ifdef SUPPORT_XMS
7134: if(support_xms) {
7135: REG8(AL) = 0x80;
7136: } else
7137: #endif
7138: REG8(AL) = 0x00;
7139: break;
7140: case 0x10:
7141: REG16(BX) = XMS_OFFSET;
7142: SREG(ES) = XMS_TOP >> 4;
7143: i386_load_segment_descriptor(ES);
1.1 root 7144: break;
7145: default:
7146: REG16(AX) = 0x01;
1.1.1.3 root 7147: m_CF = 1;
1.1 root 7148: break;
7149: }
7150: }
7151:
7152: inline void msdos_int_2fh_4ah()
7153: {
1.1.1.19 root 7154: // hma is not installed
1.1 root 7155: switch(REG8(AL)) {
7156: case 0x01:
7157: case 0x02:
1.1.1.19 root 7158: // hma is not used
1.1 root 7159: REG16(BX) = 0;
1.1.1.3 root 7160: SREG(ES) = 0xffff;
7161: i386_load_segment_descriptor(ES);
1.1 root 7162: REG16(DI) = 0xffff;
7163: break;
1.1.1.19 root 7164: case 0x03:
7165: // unable to allocate
7166: REG16(DI) = 0xffff;
7167: break;
7168: case 0x04:
7169: // function not supported, do not clear AX
7170: break;
1.1 root 7171: default:
7172: REG16(AX) = 0x01;
1.1.1.3 root 7173: m_CF = 1;
1.1 root 7174: break;
7175: }
7176: }
7177:
7178: inline void msdos_int_2fh_4fh()
7179: {
7180: switch(REG8(AL)) {
7181: case 0x00:
7182: REG16(AX) = 0;
7183: REG8(DL) = 1; // major version
7184: REG8(DH) = 0; // minor version
7185: break;
7186: case 0x01:
7187: REG16(AX) = 0;
7188: REG16(BX) = active_code_page;
7189: break;
7190: default:
7191: REG16(AX) = 0x01;
1.1.1.3 root 7192: m_CF = 1;
1.1 root 7193: break;
7194: }
7195: }
7196:
7197: inline void msdos_int_2fh_aeh()
7198: {
7199: switch(REG8(AL)) {
7200: case 0x00:
7201: REG8(AL) = 0;
7202: break;
7203: case 0x01:
7204: {
7205: char command[MAX_PATH];
7206: memset(command, 0, sizeof(command));
1.1.1.3 root 7207: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 7208:
7209: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7210: param->env_seg = 0;
7211: param->cmd_line.w.l = 44;
7212: param->cmd_line.w.h = (WORK_TOP >> 4);
7213: param->fcb1.w.l = 24;
7214: param->fcb1.w.h = (WORK_TOP >> 4);
7215: param->fcb2.w.l = 24;
7216: param->fcb2.w.h = (WORK_TOP >> 4);
7217:
7218: memset(mem + WORK_TOP + 24, 0x20, 20);
7219:
7220: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 7221: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
7222: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 7223: cmd_line->cmd[cmd_line->len] = 0x0d;
7224:
7225: if(msdos_process_exec(command, param, 0)) {
7226: REG16(AX) = 0x02;
1.1.1.3 root 7227: m_CF = 1;
1.1 root 7228: }
7229: }
7230: break;
7231: default:
7232: REG16(AX) = 0x01;
1.1.1.3 root 7233: m_CF = 1;
1.1 root 7234: break;
7235: }
7236: }
7237:
7238: inline void msdos_int_2fh_b7h()
7239: {
7240: switch(REG8(AL)) {
7241: case 0x00:
7242: // append is not installed
7243: REG8(AL) = 0;
7244: break;
7245: default:
7246: REG16(AX) = 0x01;
1.1.1.3 root 7247: m_CF = 1;
1.1 root 7248: break;
7249: }
7250: }
7251:
1.1.1.19 root 7252: inline void msdos_int_67h_40h()
7253: {
7254: if(!support_ems) {
7255: REG8(AH) = 0x84;
7256: } else {
7257: REG8(AH) = 0x00;
7258: }
7259: }
7260:
7261: inline void msdos_int_67h_41h()
7262: {
7263: if(!support_ems) {
7264: REG8(AH) = 0x84;
7265: } else {
7266: REG8(AH) = 0x00;
7267: REG16(BX) = EMS_TOP >> 4;
7268: }
7269: }
7270:
7271: inline void msdos_int_67h_42h()
7272: {
7273: if(!support_ems) {
7274: REG8(AH) = 0x84;
7275: } else {
7276: REG8(AH) = 0x00;
7277: REG16(BX) = free_ems_pages;
7278: REG16(DX) = MAX_EMS_PAGES;
7279: }
7280: }
7281:
7282: inline void msdos_int_67h_43h()
7283: {
7284: if(!support_ems) {
7285: REG8(AH) = 0x84;
7286: } else if(REG16(BX) > MAX_EMS_PAGES) {
7287: REG8(AH) = 0x87;
7288: } else if(REG16(BX) > free_ems_pages) {
7289: REG8(AH) = 0x88;
7290: } else if(REG16(BX) == 0) {
7291: REG8(AH) = 0x89;
7292: } else {
7293: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7294: if(!ems_handles[i].allocated) {
7295: ems_allocate_pages(i, REG16(BX));
7296: REG8(AH) = 0x00;
7297: REG16(DX) = i;
7298: return;
7299: }
7300: }
7301: REG8(AH) = 0x85;
7302: }
7303: }
7304:
7305: inline void msdos_int_67h_44h()
7306: {
7307: if(!support_ems) {
7308: REG8(AH) = 0x84;
7309: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7310: REG8(AH) = 0x83;
7311: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
7312: REG8(AH) = 0x8a;
7313: // } else if(!(REG8(AL) < 4)) {
7314: // REG8(AH) = 0x8b;
7315: } else if(REG16(BX) == 0xffff) {
7316: ems_unmap_page(REG8(AL) & 3);
7317: REG8(AH) = 0x00;
7318: } else {
7319: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
7320: REG8(AH) = 0x00;
7321: }
7322: }
7323:
7324: inline void msdos_int_67h_45h()
7325: {
7326: if(!support_ems) {
7327: REG8(AH) = 0x84;
7328: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7329: REG8(AH) = 0x83;
7330: } else {
7331: ems_release_pages(REG16(DX));
7332: REG8(AH) = 0x00;
7333: }
7334: }
7335:
7336: inline void msdos_int_67h_46h()
7337: {
7338: if(!support_ems) {
7339: REG8(AH) = 0x84;
7340: } else {
7341: REG16(AX) = 0x0032; // EMS 3.2
7342: // REG16(AX) = 0x0040; // EMS 4.0
7343: }
7344: }
7345:
7346: inline void msdos_int_67h_47h()
7347: {
7348: // NOTE: the map data should be stored in the specified ems page, not process data
7349: process_t *process = msdos_process_info_get(current_psp);
7350:
7351: if(!support_ems) {
7352: REG8(AH) = 0x84;
7353: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7354: // REG8(AH) = 0x83;
7355: } else if(process->ems_pages_stored) {
7356: REG8(AH) = 0x8d;
7357: } else {
7358: for(int i = 0; i < 4; i++) {
7359: process->ems_pages[i].handle = ems_pages[i].handle;
7360: process->ems_pages[i].page = ems_pages[i].page;
7361: process->ems_pages[i].mapped = ems_pages[i].mapped;
7362: }
7363: process->ems_pages_stored = true;
7364: REG8(AH) = 0x00;
7365: }
7366: }
7367:
7368: inline void msdos_int_67h_48h()
7369: {
7370: // NOTE: the map data should be restored from the specified ems page, not process data
7371: process_t *process = msdos_process_info_get(current_psp);
7372:
7373: if(!support_ems) {
7374: REG8(AH) = 0x84;
7375: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7376: // REG8(AH) = 0x83;
7377: } else if(!process->ems_pages_stored) {
7378: REG8(AH) = 0x8e;
7379: } else {
7380: for(int i = 0; i < 4; i++) {
7381: if(process->ems_pages[i].mapped) {
7382: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
7383: } else {
7384: ems_unmap_page(i);
7385: }
7386: }
7387: process->ems_pages_stored = false;
7388: REG8(AH) = 0x00;
7389: }
7390: }
7391:
7392: inline void msdos_int_67h_4bh()
7393: {
7394: if(!support_ems) {
7395: REG8(AH) = 0x84;
7396: } else {
7397: REG8(AH) = 0x00;
7398: REG16(BX) = 0;
7399: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7400: if(ems_handles[i].allocated) {
7401: REG16(BX)++;
7402: }
7403: }
7404: }
7405: }
7406:
7407: inline void msdos_int_67h_4ch()
7408: {
7409: if(!support_ems) {
7410: REG8(AH) = 0x84;
7411: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7412: REG8(AH) = 0x83;
7413: } else {
7414: REG8(AH) = 0x00;
7415: REG16(BX) = ems_handles[REG16(DX)].pages;
7416: }
7417: }
7418:
7419: inline void msdos_int_67h_4dh()
7420: {
7421: if(!support_ems) {
7422: REG8(AH) = 0x84;
7423: } else {
7424: REG8(AH) = 0x00;
7425: REG16(BX) = 0;
7426: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7427: if(ems_handles[i].allocated) {
7428: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
7429: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
7430: REG16(BX)++;
7431: }
7432: }
7433: }
7434: }
7435:
1.1.1.20! root 7436: inline void msdos_int_67h_4eh()
! 7437: {
! 7438: if(!support_ems) {
! 7439: REG8(AH) = 0x84;
! 7440: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
! 7441: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
! 7442: // save page map
! 7443: for(int i = 0; i < 4; i++) {
! 7444: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
! 7445: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
! 7446: }
! 7447: }
! 7448: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
! 7449: // restore page map
! 7450: for(int i = 0; i < 4; i++) {
! 7451: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
! 7452: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
! 7453:
! 7454: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
! 7455: ems_map_page(i, handle, page);
! 7456: } else {
! 7457: ems_unmap_page(i);
! 7458: }
! 7459: }
! 7460: }
! 7461: REG8(AH) = 0x00;
! 7462: } else if(REG8(AL) == 0x03) {
! 7463: REG8(AH) = 0x00;
! 7464: REG8(AL) = (2 + 2) * 4;
! 7465: } else {
! 7466: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
! 7467: REG8(AH) = 0x8f;
! 7468: }
! 7469: }
! 7470:
! 7471: inline void msdos_int_67h_50h()
! 7472: {
! 7473: if(!support_ems) {
! 7474: REG8(AH) = 0x84;
! 7475: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
! 7476: REG8(AH) = 0x83;
! 7477: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
! 7478: for(int i = 0; i < REG16(CX); i++) {
! 7479: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
! 7480: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
! 7481:
! 7482: if(REG8(AL) == 0x01) {
! 7483: physical = ((physical << 4) - EMS_TOP) / 0x4000;
! 7484: }
! 7485: // if(!(physical < 4)) {
! 7486: // REG8(AH) = 0x8b;
! 7487: // return;
! 7488: // } else
! 7489: if(logical == 0xffff) {
! 7490: ems_unmap_page(physical & 3);
! 7491: } else if(logical < ems_handles[REG16(DX)].pages) {
! 7492: ems_map_page(physical & 3, REG16(DX), logical);
! 7493: } else {
! 7494: REG8(AH) = 0x8a;
! 7495: return;
! 7496: }
! 7497: }
! 7498: REG8(AH) = 0x00;
! 7499: } else {
! 7500: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
! 7501: REG8(AH) = 0x8f;
! 7502: }
! 7503: }
! 7504:
1.1.1.19 root 7505: inline void msdos_int_67h_51h()
7506: {
7507: if(!support_ems) {
7508: REG8(AH) = 0x84;
7509: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7510: REG8(AH) = 0x83;
7511: } else if(REG16(BX) > MAX_EMS_PAGES) {
7512: REG8(AH) = 0x87;
7513: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
7514: REG8(AH) = 0x88;
7515: } else {
7516: ems_reallocate_pages(REG16(DX), REG16(BX));
7517: REG8(AH) = 0x00;
7518: }
7519: }
7520:
1.1.1.20! root 7521: inline void msdos_int_67h_52h()
! 7522: {
! 7523: if(!support_ems) {
! 7524: REG8(AH) = 0x84;
! 7525: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
! 7526: REG8(AH) = 0x83;
! 7527: } else if(REG8(AL) == 0x00) {
! 7528: REG8(AL) = 0x00; // handle is volatile
! 7529: REG8(AH) = 0x00;
! 7530: } else if(REG8(AL) == 0x01) {
! 7531: if(REG8(BL) == 0x00) {
! 7532: REG8(AH) = 0x00;
! 7533: } else {
! 7534: REG8(AH) = 0x90; // undefined attribute type
! 7535: }
! 7536: } else if(REG8(AL) == 0x02) {
! 7537: REG8(AL) = 0x00; // only volatile handles supported
! 7538: REG8(AH) = 0x00;
! 7539: } else {
! 7540: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
! 7541: REG8(AH) = 0x8f;
! 7542: }
! 7543: }
! 7544:
1.1.1.19 root 7545: inline void msdos_int_67h_53h()
7546: {
7547: if(!support_ems) {
7548: REG8(AH) = 0x84;
7549: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7550: REG8(AH) = 0x83;
7551: } else if(REG8(AL) == 0x00) {
7552: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
7553: REG8(AH) = 0x00;
7554: } else if(REG8(AL) == 0x01) {
7555: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7556: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
7557: REG8(AH) = 0xa1;
7558: return;
7559: }
7560: }
7561: REG8(AH) = 0x00;
7562: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
7563: } else {
7564: // 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 7565: REG8(AH) = 0x8f;
1.1.1.19 root 7566: }
7567: }
7568:
7569: inline void msdos_int_67h_54h()
7570: {
7571: if(!support_ems) {
7572: REG8(AH) = 0x84;
7573: } else if(REG8(AL) == 0x00) {
7574: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7575: if(ems_handles[i].allocated) {
7576: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
7577: } else {
7578: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
7579: }
7580: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
7581: }
7582: REG8(AH) = 0x00;
7583: REG8(AL) = MAX_EMS_HANDLES;
7584: } else if(REG8(AL) == 0x01) {
7585: REG8(AH) = 0xa0; // not found
7586: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7587: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
7588: REG8(AH) = 0x00;
7589: REG16(DX) = i;
7590: break;
7591: }
7592: }
7593: } else if(REG8(AL) == 0x02) {
7594: REG8(AH) = 0x00;
7595: REG16(BX) = MAX_EMS_HANDLES;
7596: } else {
7597: // 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 7598: REG8(AH) = 0x8f;
! 7599: }
! 7600: }
! 7601:
! 7602: inline void msdos_int_67h_57h_tmp()
! 7603: {
! 7604: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
! 7605: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
! 7606: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
! 7607: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
! 7608: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
! 7609: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
! 7610: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
! 7611: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
! 7612: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
! 7613:
! 7614: UINT8 *src_buffer, *dest_buffer;
! 7615: UINT32 src_addr, dest_addr;
! 7616: UINT32 src_addr_max, dest_addr_max;
! 7617:
! 7618: if(src_type == 0) {
! 7619: src_buffer = mem;
! 7620: src_addr = (src_seg << 4) + src_ofs;
! 7621: src_addr_max = MAX_MEM;
! 7622: } else {
! 7623: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
! 7624: REG8(AH) = 0x83;
! 7625: return;
! 7626: } else if(!(src_seg < ems_handles[src_handle].pages)) {
! 7627: REG8(AH) = 0x8a;
! 7628: return;
! 7629: }
! 7630: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
! 7631: src_addr = src_ofs;
! 7632: src_addr_max = 0x4000;
! 7633: }
! 7634: if(dest_type == 0) {
! 7635: dest_buffer = mem;
! 7636: dest_addr = (dest_seg << 4) + dest_ofs;
! 7637: dest_addr_max = MAX_MEM;
! 7638: } else {
! 7639: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
! 7640: REG8(AH) = 0x83;
! 7641: return;
! 7642: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
! 7643: REG8(AH) = 0x8a;
! 7644: return;
! 7645: }
! 7646: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
! 7647: dest_addr = dest_ofs;
! 7648: dest_addr_max = 0x4000;
! 7649: }
! 7650: for(int i = 0; i < copy_length; i++) {
! 7651: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
! 7652: if(REG8(AL) == 0x00) {
! 7653: dest_buffer[dest_addr++] = src_buffer[src_addr++];
! 7654: } else if(REG8(AL) == 0x01) {
! 7655: UINT8 tmp = dest_buffer[dest_addr];
! 7656: dest_buffer[dest_addr++] = src_buffer[src_addr];
! 7657: src_buffer[src_addr++] = tmp;
! 7658: }
! 7659: } else {
! 7660: REG8(AH) = 0x93;
! 7661: return;
! 7662: }
! 7663: }
! 7664: REG8(AH) = 0x80;
! 7665: }
! 7666:
! 7667: inline void msdos_int_67h_57h()
! 7668: {
! 7669: if(!support_ems) {
! 7670: REG8(AH) = 0x84;
! 7671: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
! 7672: struct {
! 7673: UINT16 handle;
! 7674: UINT16 page;
! 7675: bool mapped;
! 7676: } tmp_pages[4];
! 7677:
! 7678: // unmap pages to copy memory data to ems buffer
! 7679: for(int i = 0; i < 4; i++) {
! 7680: tmp_pages[i].handle = ems_pages[i].handle;
! 7681: tmp_pages[i].page = ems_pages[i].page;
! 7682: tmp_pages[i].mapped = ems_pages[i].mapped;
! 7683: ems_unmap_page(i);
! 7684: }
! 7685:
! 7686: // run move/exchange operation
! 7687: msdos_int_67h_57h_tmp();
! 7688:
! 7689: // restore unmapped pages
! 7690: for(int i = 0; i < 4; i++) {
! 7691: if(tmp_pages[i].mapped) {
! 7692: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
! 7693: }
! 7694: }
! 7695: } else {
! 7696: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
! 7697: REG8(AH) = 0x8f;
! 7698: }
! 7699: }
! 7700:
! 7701: inline void msdos_int_67h_58h()
! 7702: {
! 7703: if(!support_ems) {
! 7704: REG8(AH) = 0x84;
! 7705: } else if(REG8(AL) == 0x00) {
! 7706: for(int i = 0; i < 4; i++) {
! 7707: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
! 7708: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
! 7709: }
! 7710: REG8(AH) = 0x00;
! 7711: REG16(CX) = 4;
! 7712: } else if(REG8(AL) == 0x01) {
! 7713: REG8(AH) = 0x00;
! 7714: REG16(CX) = 4;
! 7715: } else {
! 7716: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
! 7717: REG8(AH) = 0x8f;
! 7718: }
! 7719: }
! 7720:
! 7721: inline void msdos_int_67h_5ah()
! 7722: {
! 7723: if(!support_ems) {
1.1.1.19 root 7724: REG8(AH) = 0x84;
1.1.1.20! root 7725: } else if(REG16(BX) > MAX_EMS_PAGES) {
! 7726: REG8(AH) = 0x87;
! 7727: } else if(REG16(BX) > free_ems_pages) {
! 7728: REG8(AH) = 0x88;
! 7729: // } else if(REG16(BX) == 0) {
! 7730: // REG8(AH) = 0x89;
! 7731: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
! 7732: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
! 7733: if(!ems_handles[i].allocated) {
! 7734: ems_allocate_pages(i, REG16(BX));
! 7735: REG8(AH) = 0x00;
! 7736: REG16(DX) = i;
! 7737: return;
! 7738: }
! 7739: }
! 7740: REG8(AH) = 0x85;
! 7741: } else {
! 7742: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
! 7743: REG8(AH) = 0x8f;
1.1.1.19 root 7744: }
7745: }
7746:
7747: #ifdef SUPPORT_XMS
7748:
7749: inline void msdos_call_xms_00h()
7750: {
7751: REG16(AX) = 0x0270; // V2.70
7752: REG16(BX) = 0x0000;
7753: // REG16(DX) = 0x0000; // hma does not exist
7754: REG16(DX) = 0x0001; // hma does exist
7755: }
7756:
7757: inline void msdos_call_xms_01h()
7758: {
7759: REG16(AX) = 0x0000;
7760: // REG8(BL) = 0x90; // hma does not exist
7761: REG8(BL) = 0x91; // hma is already used
7762: }
7763:
7764: inline void msdos_call_xms_02h()
7765: {
7766: REG16(AX) = 0x0000;
7767: // REG8(BL) = 0x90; // hma does not exist
7768: REG8(BL) = 0x91; // hma is already used
7769: }
7770:
7771: inline void msdos_call_xms_03h()
7772: {
7773: i386_set_a20_line(1);
7774: REG16(AX) = 0x0001;
7775: REG8(BL) = 0x00;
7776: }
7777:
7778: inline void msdos_call_xms_04h()
7779: {
7780: if((m_a20_mask >> 20) & 1) {
7781: i386_set_a20_line(0);
7782: REG16(AX) = 0x0001;
7783: REG8(BL) = 0x00;
7784: } else {
7785: REG16(AX) = 0x0000;
7786: REG8(BL) = 0x94;
7787: }
7788: }
7789:
7790: inline void msdos_call_xms_05h()
7791: {
7792: i386_set_a20_line(1);
7793: REG16(AX) = 0x0001;
7794: REG8(BL) = 0x00;
7795: }
7796:
7797: void msdos_call_xms_06h()
7798: {
7799: if((m_a20_mask >> 20) & 1) {
7800: i386_set_a20_line(0);
7801: REG16(AX) = 0x0001;
7802: REG8(BL) = 0x00;
7803: } else {
7804: REG16(AX) = 0x0000;
7805: REG8(BL) = 0x94;
7806: }
7807: }
7808:
7809: inline void msdos_call_xms_07h()
7810: {
7811: REG16(AX) = (m_a20_mask >> 20) & 1;
7812: REG8(BL) = 0x00;
7813: }
7814:
7815: inline void msdos_call_xms_08h()
7816: {
7817: REG16(AX) = REG16(DX) = 0x0000;
7818:
7819: int mcb_seg = EMB_TOP >> 4;
7820:
7821: while(1) {
7822: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
7823:
7824: if(mcb->psp == 0) {
7825: if(REG16(AX) < mcb->size_kb()) {
7826: REG16(AX) = mcb->size_kb();
7827: }
7828: REG16(DX) += mcb->size_kb();
7829: }
7830: if(mcb->mz == 'Z') {
7831: break;
7832: }
7833: mcb_seg += 1 + mcb->paragraphs();
7834: }
7835:
7836: if(REG16(AX) == 0 && REG16(DX) == 0) {
7837: REG8(BL) = 0xa0;
7838: } else {
7839: REG8(BL) = 0x00;
7840: }
7841: }
7842:
7843: inline void msdos_call_xms_09h()
7844: {
7845: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
7846: if(!xms_handles[i].allocated) {
7847: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
7848: xms_handles[i].size_kb = REG16(DX);
7849: xms_handles[i].lock = 0;
7850: xms_handles[i].allocated = true;
7851:
7852: REG16(AX) = 0x0001;
7853: REG16(DX) = i;
7854: REG8(BL) = 0x00;
7855: } else {
7856: REG16(AX) = REG16(DX) = 0x0000;
7857: REG8(BL) = 0xa0;
7858: }
7859: return;
7860: }
7861: }
7862: REG16(AX) = REG16(DX) = 0x0000;
7863: REG8(BL) = 0xa1;
7864: }
7865:
7866: inline void msdos_call_xms_0ah()
7867: {
7868: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
7869: REG16(AX) = 0x0000;
7870: REG8(BL) = 0xa2;
7871: } else if(xms_handles[REG16(DX)].lock > 0) {
7872: REG16(AX) = 0x0000;
7873: REG8(BL) = 0xab;
7874: } else {
7875: msdos_mem_free(xms_handles[REG16(DX)].seg);
7876: xms_handles[REG16(DX)].allocated = false;
7877:
7878: REG16(AX) = 0x0001;
7879: REG8(BL) = 0x00;
7880: }
7881: }
7882:
7883: inline void msdos_call_xms_0bh()
7884: {
7885: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
7886: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
7887: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
7888: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
7889: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
7890:
7891: UINT8 *src_buffer, *dest_buffer;
7892: UINT32 src_addr_max, dest_addr_max;
7893:
7894: if(src_handle == 0) {
7895: src_buffer = mem;
7896: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
7897: src_addr_max = MAX_MEM;
7898: } else {
7899: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
7900: REG16(AX) = 0x0000;
7901: REG8(BL) = 0xa3;
7902: return;
7903: }
7904: src_buffer = mem + (xms_handles[src_handle].seg << 4);
7905: src_addr_max = xms_handles[src_handle].size_kb * 1024;
7906: }
7907: if(dest_handle == 0) {
7908: dest_buffer = mem;
7909: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
7910: dest_addr_max = MAX_MEM;
7911: } else {
7912: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
7913: REG16(AX) = 0x0000;
7914: REG8(BL) = 0xa5;
7915: return;
7916: }
7917: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
7918: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
7919: }
7920: for(int i = 0; i < copy_length; i++) {
7921: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
7922: dest_buffer[dest_addr++] = src_buffer[src_addr++];
7923: } else {
7924: break;
7925: }
7926: }
7927: REG16(AX) = 0x0001;
7928: REG8(BL) = 0x00;
7929: }
7930:
7931: inline void msdos_call_xms_0ch()
7932: {
7933: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
7934: REG16(AX) = 0x0000;
7935: REG8(BL) = 0xa2;
7936: } else {
7937: xms_handles[REG16(DX)].lock++;
7938: REG16(AX) = 0x0001;
7939: REG8(BL) = 0x00;
7940: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
7941: REG16(DX) = (addr >> 16) & 0xffff;
7942: REG16(BX) = (addr ) & 0xffff;
7943: }
7944: }
7945:
7946: inline void msdos_call_xms_0dh()
7947: {
7948: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
7949: REG16(AX) = 0x0000;
7950: REG8(BL) = 0xa2;
7951: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
7952: REG16(AX) = 0x0000;
7953: REG8(BL) = 0xaa;
7954: } else {
7955: xms_handles[REG16(DX)].lock--;
7956: REG16(AX) = 0x0001;
7957: REG8(BL) = 0x00;
7958: }
7959: }
7960:
7961: inline void msdos_call_xms_0eh()
7962: {
7963: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
7964: REG16(AX) = 0x0000;
7965: REG8(BL) = 0xa2;
7966: } else {
7967: REG16(AX) = 0x0001;
7968: REG8(BH) = xms_handles[REG16(DX)].lock;
7969: REG8(BL) = 0x00;
7970: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
7971: if(!xms_handles[i].allocated) {
7972: REG8(BL)++;
7973: }
7974: }
7975: REG16(DX) = xms_handles[REG16(DX)].size_kb;
7976: }
7977: }
7978:
7979: inline void msdos_call_xms_0fh()
7980: {
7981: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
7982: REG16(AX) = 0x0000;
7983: REG8(BL) = 0xa2;
7984: } else if(xms_handles[REG16(DX)].lock > 0) {
7985: REG16(AX) = 0x0000;
7986: REG8(BL) = 0xab;
7987: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
7988: REG16(AX) = 0x0000;
7989: REG8(BL) = 0xa0;
7990: } else {
7991: REG16(AX) = 0x0001;
7992: REG8(BL) = 0x00;
7993: }
7994: }
7995:
7996: inline void msdos_call_xms_10h()
7997: {
7998: int seg;
7999:
8000: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
8001: REG16(AX) = 0x0001;
8002: REG16(BX) = seg;
8003: } else {
8004: REG16(AX) = 0x0000;
8005: REG8(BL) = 0xb0;
8006: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
8007: }
8008: }
8009:
8010: inline void msdos_call_xms_11h()
8011: {
8012: int mcb_seg = REG16(DX) - 1;
8013: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
8014:
8015: if(mcb->mz == 'M' || mcb->mz == 'Z') {
8016: msdos_mem_free(REG16(DX));
8017: REG16(AX) = 0x0001;
8018: REG8(BL) = 0x00;
8019: } else {
8020: REG16(AX) = 0x0000;
8021: REG8(BL) = 0xb2;
8022: }
8023: }
8024:
8025: inline void msdos_call_xms_12h()
8026: {
8027: int mcb_seg = REG16(DX) - 1;
8028: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
8029: int max_paragraphs;
8030:
8031: if(mcb->mz == 'M' || mcb->mz == 'Z') {
8032: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
8033: REG16(AX) = 0x0001;
8034: REG8(BL) = 0x00;
8035: } else {
8036: REG16(AX) = 0x0000;
8037: REG8(BL) = 0xb0;
8038: REG16(DX) = max_paragraphs;
8039: }
8040: } else {
8041: REG16(AX) = 0x0000;
8042: REG8(BL) = 0xb2;
8043: }
8044: }
8045:
8046: #endif
8047:
1.1 root 8048: void msdos_syscall(unsigned num)
8049: {
8050: switch(num) {
8051: case 0x00:
8052: error("division by zero\n");
8053: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8054: break;
8055: case 0x04:
8056: error("overflow\n");
8057: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8058: break;
8059: case 0x06:
8060: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 8061: if(!ignore_illegal_insn) {
8062: error("illegal instruction\n");
8063: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8064: } else {
8065: #if defined(HAS_I386)
8066: m_eip++;
8067: #else
8068: m_pc++;
8069: #endif
8070: }
1.1 root 8071: break;
1.1.1.8 root 8072: case 0x08:
1.1.1.14 root 8073: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 8074: case 0x09:
8075: case 0x0a:
8076: case 0x0b:
8077: case 0x0c:
8078: case 0x0d:
8079: case 0x0e:
8080: case 0x0f:
8081: // EOI
8082: pic[0].isr &= ~(1 << (num - 0x08));
8083: pic_update();
8084: break;
1.1 root 8085: case 0x10:
8086: // PC BIOS - Video
1.1.1.14 root 8087: if(!restore_console_on_exit) {
1.1.1.15 root 8088: change_console_size(scr_width, scr_height);
1.1 root 8089: }
1.1.1.3 root 8090: m_CF = 0;
1.1 root 8091: switch(REG8(AH)) {
1.1.1.16 root 8092: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 8093: case 0x01: pcbios_int_10h_01h(); break;
8094: case 0x02: pcbios_int_10h_02h(); break;
8095: case 0x03: pcbios_int_10h_03h(); break;
8096: case 0x05: pcbios_int_10h_05h(); break;
8097: case 0x06: pcbios_int_10h_06h(); break;
8098: case 0x07: pcbios_int_10h_07h(); break;
8099: case 0x08: pcbios_int_10h_08h(); break;
8100: case 0x09: pcbios_int_10h_09h(); break;
8101: case 0x0a: pcbios_int_10h_0ah(); break;
8102: case 0x0b: break;
8103: case 0x0c: break;
8104: case 0x0d: break;
8105: case 0x0e: pcbios_int_10h_0eh(); break;
8106: case 0x0f: pcbios_int_10h_0fh(); break;
8107: case 0x10: break;
1.1.1.14 root 8108: case 0x11: pcbios_int_10h_11h(); break;
8109: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 8110: case 0x13: pcbios_int_10h_13h(); break;
8111: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 8112: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.11 root 8113: case 0x1b: break;
1.1 root 8114: case 0x1c: REG8(AL) = 0x00; break;
8115: case 0x1d: pcbios_int_10h_1dh(); break;
8116: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.11 root 8117: case 0xef: REG16(DX) = 0xffff; break;
1.1 root 8118: case 0xfe: pcbios_int_10h_feh(); break;
8119: case 0xff: pcbios_int_10h_ffh(); break;
8120: default:
1.1.1.14 root 8121: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 8122: break;
8123: }
8124: break;
8125: case 0x11:
8126: // PC BIOS - Get Equipment List
1.1.1.11 root 8127: #ifdef SUPPORT_FPU
8128: REG16(AX) = 0x22;
8129: #else
1.1 root 8130: REG16(AX) = 0x20;
1.1.1.11 root 8131: #endif
1.1 root 8132: break;
8133: case 0x12:
8134: // PC BIOS - Get Memory Size
8135: REG16(AX) = MEMORY_END / 1024;
8136: break;
8137: case 0x13:
8138: // PC BIOS - Disk
8139: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8140: REG8(AH) = 0xff;
1.1.1.3 root 8141: m_CF = 1;
1.1 root 8142: break;
8143: case 0x14:
8144: // PC BIOS - Serial I/O
8145: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8146: REG8(AH) = 0xff;
1.1.1.3 root 8147: m_CF = 1;
1.1 root 8148: break;
8149: case 0x15:
8150: // PC BIOS
1.1.1.3 root 8151: m_CF = 0;
1.1 root 8152: switch(REG8(AH)) {
1.1.1.14 root 8153: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 8154: case 0x23: pcbios_int_15h_23h(); break;
8155: case 0x24: pcbios_int_15h_24h(); break;
8156: case 0x49: pcbios_int_15h_49h(); break;
8157: case 0x86: pcbios_int_15h_86h(); break;
8158: case 0x87: pcbios_int_15h_87h(); break;
8159: case 0x88: pcbios_int_15h_88h(); break;
8160: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.3 root 8161: #if defined(HAS_I386)
1.1 root 8162: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 8163: #endif
1.1 root 8164: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.17 root 8165: case 0xe8:
8166: switch(REG8(AL)) {
8167: #if defined(HAS_I386)
8168: case 0x01: pcbios_int_15h_e801h(); break;
8169: #endif
8170: default:
8171: REG8(AH)=0x86;
8172: m_CF = 1;
8173: }
8174: break;
1.1 root 8175: default:
8176: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8177: REG8(AH)=0x86;
1.1.1.3 root 8178: m_CF = 1;
1.1 root 8179: break;
8180: }
8181: break;
8182: case 0x16:
8183: // PC BIOS - Keyboard
1.1.1.3 root 8184: m_CF = 0;
1.1 root 8185: switch(REG8(AH)) {
8186: case 0x00: pcbios_int_16h_00h(); break;
8187: case 0x01: pcbios_int_16h_01h(); break;
8188: case 0x02: pcbios_int_16h_02h(); break;
8189: case 0x03: pcbios_int_16h_03h(); break;
8190: case 0x05: pcbios_int_16h_05h(); break;
8191: case 0x10: pcbios_int_16h_00h(); break;
8192: case 0x11: pcbios_int_16h_01h(); break;
8193: case 0x12: pcbios_int_16h_12h(); break;
8194: case 0x13: pcbios_int_16h_13h(); break;
8195: case 0x14: pcbios_int_16h_14h(); break;
8196: default:
1.1.1.14 root 8197: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 8198: break;
8199: }
8200: break;
8201: case 0x17:
8202: // PC BIOS - Printer
8203: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8204: break;
8205: case 0x1a:
8206: // PC BIOS - Timer
1.1.1.3 root 8207: m_CF = 0;
1.1 root 8208: switch(REG8(AH)) {
8209: case 0x00: pcbios_int_1ah_00h(); break;
8210: case 0x01: break;
8211: case 0x02: pcbios_int_1ah_02h(); break;
8212: case 0x03: break;
8213: case 0x04: pcbios_int_1ah_04h(); break;
8214: case 0x05: break;
8215: case 0x0a: pcbios_int_1ah_0ah(); break;
8216: case 0x0b: break;
1.1.1.14 root 8217: case 0x35: break; // Word Perfect Third Party Interface?
8218: case 0x36: break; // Word Perfect Third Party Interface
8219: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 8220: default:
8221: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8222: break;
8223: }
8224: break;
8225: case 0x20:
1.1.1.3 root 8226: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 8227: break;
8228: case 0x21:
8229: // MS-DOS System Call
1.1.1.3 root 8230: m_CF = 0;
1.1 root 8231: switch(REG8(AH)) {
8232: case 0x00: msdos_int_21h_00h(); break;
8233: case 0x01: msdos_int_21h_01h(); break;
8234: case 0x02: msdos_int_21h_02h(); break;
8235: case 0x03: msdos_int_21h_03h(); break;
8236: case 0x04: msdos_int_21h_04h(); break;
8237: case 0x05: msdos_int_21h_05h(); break;
8238: case 0x06: msdos_int_21h_06h(); break;
8239: case 0x07: msdos_int_21h_07h(); break;
8240: case 0x08: msdos_int_21h_08h(); break;
8241: case 0x09: msdos_int_21h_09h(); break;
8242: case 0x0a: msdos_int_21h_0ah(); break;
8243: case 0x0b: msdos_int_21h_0bh(); break;
8244: case 0x0c: msdos_int_21h_0ch(); break;
8245: case 0x0d: msdos_int_21h_0dh(); break;
8246: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 8247: case 0x0f: msdos_int_21h_0fh(); break;
8248: case 0x10: msdos_int_21h_10h(); break;
1.1 root 8249: case 0x11: msdos_int_21h_11h(); break;
8250: case 0x12: msdos_int_21h_12h(); break;
8251: case 0x13: msdos_int_21h_13h(); break;
1.1.1.16 root 8252: case 0x14: msdos_int_21h_14h(); break;
8253: case 0x15: msdos_int_21h_15h(); break;
1.1.1.14 root 8254: case 0x16: msdos_int_21h_16h(); break;
1.1.1.16 root 8255: case 0x17: msdos_int_21h_17h(); break;
1.1 root 8256: case 0x18: msdos_int_21h_18h(); break;
8257: case 0x19: msdos_int_21h_19h(); break;
8258: case 0x1a: msdos_int_21h_1ah(); break;
8259: case 0x1b: msdos_int_21h_1bh(); break;
8260: case 0x1c: msdos_int_21h_1ch(); break;
8261: case 0x1d: msdos_int_21h_1dh(); break;
8262: case 0x1e: msdos_int_21h_1eh(); break;
8263: case 0x1f: msdos_int_21h_1fh(); break;
8264: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 8265: case 0x21: msdos_int_21h_21h(); break;
8266: case 0x22: msdos_int_21h_22h(); break;
1.1.1.16 root 8267: case 0x23: msdos_int_21h_23h(); break;
8268: case 0x24: msdos_int_21h_24h(); break;
1.1 root 8269: case 0x25: msdos_int_21h_25h(); break;
8270: case 0x26: msdos_int_21h_26h(); break;
1.1.1.16 root 8271: case 0x27: msdos_int_21h_27h(); break;
8272: case 0x28: msdos_int_21h_28h(); break;
1.1 root 8273: case 0x29: msdos_int_21h_29h(); break;
8274: case 0x2a: msdos_int_21h_2ah(); break;
8275: case 0x2b: msdos_int_21h_2bh(); break;
8276: case 0x2c: msdos_int_21h_2ch(); break;
8277: case 0x2d: msdos_int_21h_2dh(); break;
8278: case 0x2e: msdos_int_21h_2eh(); break;
8279: case 0x2f: msdos_int_21h_2fh(); break;
8280: case 0x30: msdos_int_21h_30h(); break;
8281: case 0x31: msdos_int_21h_31h(); break;
8282: case 0x32: msdos_int_21h_32h(); break;
8283: case 0x33: msdos_int_21h_33h(); break;
8284: // 0x34: get address of indos flag
8285: case 0x35: msdos_int_21h_35h(); break;
8286: case 0x36: msdos_int_21h_36h(); break;
8287: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 8288: case 0x38: msdos_int_21h_38h(); break;
1.1 root 8289: case 0x39: msdos_int_21h_39h(0); break;
8290: case 0x3a: msdos_int_21h_3ah(0); break;
8291: case 0x3b: msdos_int_21h_3bh(0); break;
8292: case 0x3c: msdos_int_21h_3ch(); break;
8293: case 0x3d: msdos_int_21h_3dh(); break;
8294: case 0x3e: msdos_int_21h_3eh(); break;
8295: case 0x3f: msdos_int_21h_3fh(); break;
8296: case 0x40: msdos_int_21h_40h(); break;
8297: case 0x41: msdos_int_21h_41h(0); break;
8298: case 0x42: msdos_int_21h_42h(); break;
8299: case 0x43: msdos_int_21h_43h(0); break;
8300: case 0x44: msdos_int_21h_44h(); break;
8301: case 0x45: msdos_int_21h_45h(); break;
8302: case 0x46: msdos_int_21h_46h(); break;
8303: case 0x47: msdos_int_21h_47h(0); break;
8304: case 0x48: msdos_int_21h_48h(); break;
8305: case 0x49: msdos_int_21h_49h(); break;
8306: case 0x4a: msdos_int_21h_4ah(); break;
8307: case 0x4b: msdos_int_21h_4bh(); break;
8308: case 0x4c: msdos_int_21h_4ch(); break;
8309: case 0x4d: msdos_int_21h_4dh(); break;
8310: case 0x4e: msdos_int_21h_4eh(); break;
8311: case 0x4f: msdos_int_21h_4fh(); break;
8312: case 0x50: msdos_int_21h_50h(); break;
8313: case 0x51: msdos_int_21h_51h(); break;
8314: case 0x52: msdos_int_21h_52h(); break;
8315: // 0x53: translate bios parameter block to drive param bock
8316: case 0x54: msdos_int_21h_54h(); break;
8317: case 0x55: msdos_int_21h_55h(); break;
8318: case 0x56: msdos_int_21h_56h(0); break;
8319: case 0x57: msdos_int_21h_57h(); break;
8320: case 0x58: msdos_int_21h_58h(); break;
8321: case 0x59: msdos_int_21h_59h(); break;
8322: case 0x5a: msdos_int_21h_5ah(); break;
8323: case 0x5b: msdos_int_21h_5bh(); break;
8324: case 0x5c: msdos_int_21h_5ch(); break;
8325: // 0x5e: ms-network
8326: // 0x5f: ms-network
8327: case 0x60: msdos_int_21h_60h(0); break;
8328: case 0x61: msdos_int_21h_61h(); break;
8329: case 0x62: msdos_int_21h_62h(); break;
8330: case 0x63: msdos_int_21h_63h(); break;
8331: // 0x64: set device driver lockahead flag
8332: case 0x65: msdos_int_21h_65h(); break;
8333: case 0x66: msdos_int_21h_66h(); break;
8334: case 0x67: msdos_int_21h_67h(); break;
8335: case 0x68: msdos_int_21h_68h(); break;
8336: case 0x69: msdos_int_21h_69h(); break;
8337: case 0x6a: msdos_int_21h_6ah(); break;
8338: case 0x6b: msdos_int_21h_6bh(); break;
8339: case 0x6c: msdos_int_21h_6ch(0); break;
8340: // 0x6d: find first rom program
8341: // 0x6e: find next rom program
8342: // 0x6f: get/set rom scan start address
8343: // 0x70: windows95 get/set internationalization information
8344: case 0x71:
8345: // windows95 long filename functions
8346: switch(REG8(AL)) {
8347: case 0x0d: msdos_int_21h_710dh(); break;
8348: case 0x39: msdos_int_21h_39h(1); break;
8349: case 0x3a: msdos_int_21h_3ah(1); break;
8350: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.17 root 8351: case 0x41: msdos_int_21h_7141h(1); break;
1.1 root 8352: case 0x43: msdos_int_21h_43h(1); break;
8353: case 0x47: msdos_int_21h_47h(1); break;
8354: case 0x4e: msdos_int_21h_714eh(); break;
8355: case 0x4f: msdos_int_21h_714fh(); break;
8356: case 0x56: msdos_int_21h_56h(1); break;
8357: case 0x60: msdos_int_21h_60h(1); break;
8358: case 0x6c: msdos_int_21h_6ch(1); break;
8359: case 0xa0: msdos_int_21h_71a0h(); break;
8360: case 0xa1: msdos_int_21h_71a1h(); break;
8361: case 0xa6: msdos_int_21h_71a6h(); break;
8362: case 0xa7: msdos_int_21h_71a7h(); break;
8363: case 0xa8: msdos_int_21h_71a8h(); break;
8364: // 0xa9: server create/open file
8365: // 0xaa: create/terminate SUBST
8366: default:
8367: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8368: REG16(AX) = 0x7100;
1.1.1.3 root 8369: m_CF = 1;
1.1 root 8370: break;
8371: }
8372: break;
8373: // 0x72: Windows95 beta - LFN FindClose
8374: case 0x73:
8375: // windows95 fat32 functions
8376: switch(REG8(AL)) {
1.1.1.14 root 8377: case 0x00: msdos_int_21h_7300h(); break;
8378: // 0x01: set drive locking ???
8379: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 8380: case 0x03: msdos_int_21h_7303h(); break;
8381: // 0x04: set dpb to use for formatting
8382: default:
8383: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8384: REG16(AX) = 0x7300;
1.1.1.3 root 8385: m_CF = 1;
1.1 root 8386: break;
8387: }
8388: break;
8389: default:
8390: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8391: REG16(AX) = 0x01;
1.1.1.3 root 8392: m_CF = 1;
1.1 root 8393: break;
8394: }
1.1.1.3 root 8395: if(m_CF) {
1.1 root 8396: error_code = REG16(AX);
8397: }
8398: break;
8399: case 0x22:
8400: fatalerror("int 22h (terminate address)\n");
8401: case 0x23:
8402: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
8403: break;
8404: case 0x24:
8405: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8406: break;
8407: case 0x25:
8408: msdos_int_25h();
8409: break;
8410: case 0x26:
8411: msdos_int_26h();
8412: break;
8413: case 0x27:
8414: msdos_int_27h();
8415: break;
8416: case 0x28:
8417: Sleep(10);
8418: break;
8419: case 0x29:
8420: msdos_int_29h();
8421: break;
8422: case 0x2e:
8423: msdos_int_2eh();
8424: break;
8425: case 0x2f:
8426: // multiplex interrupt
8427: switch(REG8(AH)) {
8428: case 0x16: msdos_int_2fh_16h(); break;
8429: case 0x1a: msdos_int_2fh_1ah(); break;
8430: case 0x43: msdos_int_2fh_43h(); break;
8431: case 0x4a: msdos_int_2fh_4ah(); break;
8432: case 0x4f: msdos_int_2fh_4fh(); break;
8433: case 0xae: msdos_int_2fh_aeh(); break;
8434: case 0xb7: msdos_int_2fh_b7h(); break;
8435: }
8436: break;
1.1.1.19 root 8437: case 0x68:
8438: // dummy interrupt for EMS (int 67h)
8439: switch(REG8(AH)) {
8440: case 0x40: msdos_int_67h_40h(); break;
8441: case 0x41: msdos_int_67h_41h(); break;
8442: case 0x42: msdos_int_67h_42h(); break;
8443: case 0x43: msdos_int_67h_43h(); break;
8444: case 0x44: msdos_int_67h_44h(); break;
8445: case 0x45: msdos_int_67h_45h(); break;
8446: case 0x46: msdos_int_67h_46h(); break;
8447: case 0x47: msdos_int_67h_47h(); break;
8448: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20! root 8449: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
! 8450: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 8451: case 0x4b: msdos_int_67h_4bh(); break;
8452: case 0x4c: msdos_int_67h_4ch(); break;
8453: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20! root 8454: case 0x4e: msdos_int_67h_4eh(); break;
! 8455: // 0x4f: LIM EMS 4.0 - Get/Set Partial Page Map
! 8456: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 8457: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20! root 8458: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 8459: case 0x53: msdos_int_67h_53h(); break;
8460: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20! root 8461: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
! 8462: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
! 8463: case 0x57: msdos_int_67h_57h(); break;
! 8464: case 0x58: msdos_int_67h_58h(); break;
! 8465: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
! 8466: case 0x5a: msdos_int_67h_5ah(); break;
! 8467: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
! 8468: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
! 8469: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 8470: default:
8471: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8472: REG8(AH) = 0x84;
8473: break;
8474: }
8475: break;
8476: #ifdef SUPPORT_XMS
8477: case 0x69:
8478: // dummy interrupt for XMS (call far)
8479: switch(REG8(AH)) {
8480: case 0x00: msdos_call_xms_00h(); break;
8481: case 0x01: msdos_call_xms_01h(); break;
8482: case 0x02: msdos_call_xms_02h(); break;
8483: case 0x03: msdos_call_xms_03h(); break;
8484: case 0x04: msdos_call_xms_04h(); break;
8485: case 0x05: msdos_call_xms_05h(); break;
8486: case 0x06: msdos_call_xms_06h(); break;
8487: case 0x07: msdos_call_xms_07h(); break;
8488: case 0x08: msdos_call_xms_08h(); break;
8489: case 0x09: msdos_call_xms_09h(); break;
8490: case 0x0a: msdos_call_xms_0ah(); break;
8491: case 0x0b: msdos_call_xms_0bh(); break;
8492: case 0x0c: msdos_call_xms_0ch(); break;
8493: case 0x0d: msdos_call_xms_0dh(); break;
8494: case 0x0e: msdos_call_xms_0eh(); break;
8495: case 0x0f: msdos_call_xms_0fh(); break;
8496: case 0x10: msdos_call_xms_10h(); break;
8497: case 0x11: msdos_call_xms_11h(); break;
8498: case 0x12: msdos_call_xms_12h(); break;
8499: // 0x88: XMS 3.0 - Query free extended memory
8500: // 0x89: XMS 3.0 - Allocate any extended memory
8501: // 0x8e: XMS 3.0 - Get extended EMB handle information
8502: // 0x8f: XMS 3.0 - Reallocate any extended memory block
8503: default:
8504: // fatalerror("call XMS (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8505: REG16(AX) = 0x0000;
8506: REG8(BL) = 0x80;
8507: break;
8508: }
8509: break;
8510: #endif
8511: case 0x6a:
8512: // dummy interrupt for case map routine pointed in the country info
8513: if(REG8(AL) >= 0x80) {
8514: char tmp[2] = {0};
8515: tmp[0] = REG8(AL);
8516: my_strupr(tmp);
8517: REG8(AL) = tmp[0];
8518: }
8519: break;
1.1.1.8 root 8520: case 0x70:
8521: case 0x71:
8522: case 0x72:
8523: case 0x73:
8524: case 0x74:
8525: case 0x75:
8526: case 0x76:
8527: case 0x77:
8528: // EOI
8529: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
8530: pic[0].isr &= ~(1 << 2); // master
8531: }
8532: pic_update();
8533: break;
1.1 root 8534: default:
8535: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8536: break;
8537: }
8538:
8539: // update cursor position
8540: if(cursor_moved) {
8541: CONSOLE_SCREEN_BUFFER_INFO csbi;
8542: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.15 root 8543: if(!restore_console_on_exit) {
8544: scr_top = csbi.srWindow.Top;
8545: }
1.1 root 8546: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 8547: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 8548: cursor_moved = false;
8549: }
8550: }
8551:
8552: // init
8553:
8554: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
8555: {
8556: // init file handler
8557: memset(file_handler, 0, sizeof(file_handler));
8558: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
8559: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
8560: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
8561: #ifdef SUPPORT_AUX_PRN
8562: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
8563: msdos_file_handler_open(3, 0, 2, 0x80c0, 0);
8564: }
8565: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
8566: msdos_file_handler_open(4, 0, 1, 0xa8c0, 0);
8567: }
8568: #endif
8569: _dup2(0, DUP_STDIN);
8570: _dup2(1, DUP_STDOUT);
8571: _dup2(2, DUP_STDERR);
8572:
8573: // init process
8574: memset(process, 0, sizeof(process));
8575:
1.1.1.13 root 8576: // init dtainfo
8577: msdos_dta_info_init();
8578:
1.1 root 8579: // init memory
8580: memset(mem, 0, sizeof(mem));
8581:
8582: // bios data area
8583: CONSOLE_SCREEN_BUFFER_INFO csbi;
8584: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 8585: CONSOLE_FONT_INFO cfi;
8586: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
8587:
8588: int regen = min(scr_width * scr_height * 2, 0x8000);
8589: text_vram_top_address = TEXT_VRAM_TOP;
8590: text_vram_end_address = text_vram_top_address + regen;
8591: shadow_buffer_top_address = SHADOW_BUF_TOP;
8592: shadow_buffer_end_address = shadow_buffer_top_address + regen;
8593:
8594: if(regen > 0x4000) {
8595: regen = 0x8000;
8596: vram_pages = 1;
8597: } else if(regen > 0x2000) {
8598: regen = 0x4000;
8599: vram_pages = 2;
8600: } else if(regen > 0x1000) {
8601: regen = 0x2000;
8602: vram_pages = 4;
8603: } else {
8604: regen = 0x1000;
8605: vram_pages = 8;
8606: }
1.1 root 8607:
1.1.1.14 root 8608: #ifdef SUPPORT_FPU
8609: *(UINT16 *)(mem + 0x410) = 0x22;
8610: #else
1.1 root 8611: *(UINT16 *)(mem + 0x410) = 0x20;
1.1.1.14 root 8612: #endif
1.1 root 8613: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
8614: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 8615: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
8616: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 8617: *(UINT16 *)(mem + 0x44e) = 0;
8618: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 8619: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 8620: *(UINT8 *)(mem + 0x460) = 7;
8621: *(UINT8 *)(mem + 0x461) = 7;
8622: *(UINT8 *)(mem + 0x462) = 0;
8623: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 8624: *(UINT8 *)(mem + 0x465) = 0x09;
8625: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 8626: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
8627: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
8628: *(UINT8 *)(mem + 0x487) = 0x60;
8629: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
8630:
8631: // initial screen
8632: SMALL_RECT rect;
8633: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
8634: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
8635: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
8636: for(int x = 0; x < scr_width; x++) {
8637: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
8638: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
8639: }
8640: }
1.1 root 8641:
8642: // dos info
8643: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1.1.1.19 root 8644: dos_info->magic_word = 1;
1.1 root 8645: dos_info->first_mcb = MEMORY_TOP >> 4;
8646: dos_info->first_dpb.w.l = 0;
8647: dos_info->first_dpb.w.h = DPB_TOP >> 4;
8648: dos_info->first_sft.w.l = 0;
8649: dos_info->first_sft.w.h = FILE_TABLE_TOP >> 4;
1.1.1.19 root 8650: dos_info->max_sector_len = 512;
8651: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
8652: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
1.1 root 8653: dos_info->cds.w.l = 0;
8654: dos_info->cds.w.h = CDS_TOP >> 4;
8655: dos_info->fcb_table.w.l = 0;
8656: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
8657: dos_info->last_drive = 'Z' - 'A' + 1;
8658: dos_info->buffers_x = 20;
8659: dos_info->buffers_y = 0;
1.1.1.14 root 8660: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.19 root 8661: dos_info->nul_device.next_driver = 0xffffffffU;
8662: dos_info->nul_device.attributes = 0x8004U;
8663: dos_info->nul_device.strategy = 0xffffU;
8664: dos_info->nul_device.interrupt = 0xffffU;
8665: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
8666: dos_info->disk_buf_heads.w.l = 0;
8667: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.20! root 8668: dos_info->first_umb_fcb = UMB_TOP >> 4;
! 8669: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.17 root 8670:
1.1 root 8671: char *env;
8672: if((env = getenv("LASTDRIVE")) != NULL) {
8673: if(env[0] >= 'A' && env[0] <= 'Z') {
8674: dos_info->last_drive = env[0] - 'A' + 1;
8675: } else if(env[0] >= 'a' && env[0] <= 'z') {
8676: dos_info->last_drive = env[0] - 'a' + 1;
8677: }
8678: }
8679: if((env = getenv("windir")) != NULL) {
8680: if(env[0] >= 'A' && env[0] <= 'Z') {
8681: dos_info->boot_drive = env[0] - 'A' + 1;
8682: } else if(env[0] >= 'a' && env[0] <= 'z') {
8683: dos_info->boot_drive = env[0] - 'a' + 1;
8684: }
8685: }
1.1.1.3 root 8686: #if defined(HAS_I386)
1.1 root 8687: dos_info->i386_or_later = 1;
1.1.1.3 root 8688: #else
8689: dos_info->i386_or_later = 0;
8690: #endif
1.1.1.17 root 8691: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
1.1 root 8692:
1.1.1.19 root 8693: // init mcb
1.1 root 8694: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 8695:
8696: // iret table
8697: // note: int 2eh vector should address the routine in command.com,
8698: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
8699: // so move iret table into allocated memory block
8700: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
8701: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
8702: IRET_TOP = seg << 4;
8703: seg += IRET_SIZE >> 4;
8704: memset(mem + IRET_TOP, 0xcf, IRET_SIZE);
8705:
8706: // dummy xms/ems device
8707: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
8708: XMS_TOP = seg << 4;
8709: seg += XMS_SIZE >> 4;
8710:
8711: // environment
1.1 root 8712: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
8713: int env_seg = seg;
8714: int ofs = 0;
1.1.1.15 root 8715: char env_path[8192] = "", *path;
1.1 root 8716:
8717: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 8718: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
8719: sprintf(env_path, "%s;", *p + 11);
8720: break;
8721: }
8722: }
8723: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 8724: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 8725: strcat(env_path, *p + 5);
1.1.1.9 root 8726: break;
8727: }
8728: }
1.1.1.18 root 8729: if((path = getenv("MSDOS_COMSPEC")) != NULL ||
8730: (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
1.1.1.15 root 8731: strcpy(comspec_path, path);
8732: }
8733:
1.1.1.9 root 8734: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 8735: // lower to upper
8736: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
8737: int value_pos = 0;
8738: strcpy(tmp, *p);
8739: for(int i = 0;; i++) {
8740: if(tmp[i] == '=') {
8741: tmp[i] = '\0';
8742: sprintf(name, ";%s;", tmp);
8743: strcpy(value, tmp + (value_pos = i + 1));
8744: tmp[i] = '=';
8745: break;
8746: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
8747: tmp[i] = tmp[i] - 'a' + 'A';
8748: }
8749: }
1.1.1.18 root 8750: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
8751: // ignore MSDOS_COMSPEC
8752: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
8753: // ignore non standard environments
8754: } else {
1.1 root 8755: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 8756: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1 root 8757: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
8758: tmp[value_pos] = '\0';
8759: char *token = my_strtok(value, ";");
8760: while(token != NULL) {
8761: if(strlen(token) != 0) {
1.1.1.8 root 8762: char *path = msdos_remove_double_quote(token), tmp_path[MAX_PATH];
8763: if(strlen(path) != 0) {
8764: GetShortPathName(path, tmp_path, MAX_PATH);
8765: strcat(tmp, tmp_path);
8766: strcat(tmp, ";");
1.1 root 8767: }
8768: }
8769: token = my_strtok(NULL, ";");
8770: }
8771: tmp[strlen(tmp) - 1] = '\0';
8772: my_strupr(tmp);
8773: }
8774: int len = strlen(tmp);
1.1.1.14 root 8775: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 8776: fatalerror("too many environments\n");
8777: }
8778: memcpy(mem + (seg << 4) + ofs, tmp, len);
8779: ofs += len + 1;
8780: }
8781: }
8782: seg += (ENV_SIZE >> 4);
8783:
8784: // psp
8785: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
8786: current_psp = seg;
1.1.1.14 root 8787: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 8788: seg += (PSP_SIZE >> 4);
8789:
1.1.1.19 root 8790: // first free mcb in conventional memory
8791: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 8792: first_mcb = seg;
8793:
1.1.1.19 root 8794: // dummy mcb to link to umb
8795: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
8796:
8797: // first free mcb in upper memory block
1.1.1.8 root 8798: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 8799:
1.1.1.19 root 8800: #ifdef SUPPORT_XMS
8801: // first free mcb in extended memory block
8802: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
8803: #endif
8804:
8805: // interrupt vector
8806: for(int i = 0; i < 0x80; i++) {
8807: *(UINT16 *)(mem + 4 * i + 0) = i;
8808: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
8809: }
8810: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0005; // irq0
8811: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xffff;
8812: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // boot
8813: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
8814: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0000; // ems
8815: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
8816:
8817: // ems (int 67h) and xms (call far)
8818: mem[XMS_TOP + 0] = 0xcd; // int 68h (dummy)
8819: mem[XMS_TOP + 1] = 0x68;
8820: mem[XMS_TOP + 2] = 0xcf; // iret
8821: #ifdef SUPPORT_XMS
8822: if(support_xms) {
8823: mem[XMS_TOP + 4] = 0xcd; // int 69h (dummy)
8824: mem[XMS_TOP + 5] = 0x69;
8825: mem[XMS_TOP + 6] = 0xcb; // retf
8826: } else
8827: #endif
8828: mem[XMS_TOP + 4] = 0xcb; // retf
8829: memcpy(mem + XMS_TOP + 0x0a, "EMMXXXX0", 8);
8830:
8831: // case map routine (call far)
8832: mem[0xffffc] = 0xcd; // int 6ah (dummy)
8833: mem[0xffffd] = 0x6a;
8834: mem[0xffffe] = 0xcb; // retf
8835:
1.1.1.14 root 8836: // have irq0 call system timer tick
1.1.1.19 root 8837: mem[0xffff5] = 0xcd; // int 1ch
8838: mem[0xffff6] = 0x1c;
8839: mem[0xffff7] = 0xea; // jmp (IRET_TOP >> 4):0008
8840: mem[0xffff8] = 0x08;
8841: mem[0xffff9] = 0x00;
8842: mem[0xffffa] = ((IRET_TOP >> 4) ) & 0xff;
8843: mem[0xffffb] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 8844:
1.1 root 8845: // boot
8846: mem[0xffff0] = 0xf4; // halt
8847: mem[0xffff1] = 0xcd; // int 21h
8848: mem[0xffff2] = 0x21;
8849: mem[0xffff3] = 0xcb; // retf
8850:
8851: // param block
8852: // + 0: param block (22bytes)
8853: // +24: fcb1/2 (20bytes)
8854: // +44: command tail (128bytes)
8855: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8856: param->env_seg = 0;
8857: param->cmd_line.w.l = 44;
8858: param->cmd_line.w.h = (WORK_TOP >> 4);
8859: param->fcb1.w.l = 24;
8860: param->fcb1.w.h = (WORK_TOP >> 4);
8861: param->fcb2.w.l = 24;
8862: param->fcb2.w.h = (WORK_TOP >> 4);
8863:
8864: memset(mem + WORK_TOP + 24, 0x20, 20);
8865:
8866: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
8867: if(argc > 1) {
8868: sprintf(cmd_line->cmd, " %s", argv[1]);
8869: for(int i = 2; i < argc; i++) {
8870: char tmp[128];
8871: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
8872: strcpy(cmd_line->cmd, tmp);
8873: }
8874: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
8875: } else {
8876: cmd_line->len = 0;
8877: }
8878: cmd_line->cmd[cmd_line->len] = 0x0d;
8879:
8880: // system file table
1.1.1.14 root 8881: *(UINT32 *)(mem + FILE_TABLE_TOP + 0) = 0xffffffff;
8882: *(UINT16 *)(mem + FILE_TABLE_TOP + 4) = 0;
1.1 root 8883:
1.1.1.19 root 8884: // disk buffer header (from DOSBox)
8885: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
8886: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
8887: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
8888: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
8889: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
8890:
1.1 root 8891: // current directory structure
8892: msdos_cds_update(_getdrive() - 1);
8893:
8894: // fcb table
8895: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 8896: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 8897:
1.1.1.17 root 8898: // nls stuff
8899: msdos_nls_tables_init();
1.1 root 8900:
8901: // execute command
8902: if(msdos_process_exec(argv[0], param, 0)) {
8903: fatalerror("'%s' not found\n", argv[0]);
8904: }
8905: retval = 0;
8906: return(0);
8907: }
8908:
8909: #define remove_std_file(path) { \
8910: int fd = _open(path, _O_RDONLY | _O_BINARY); \
8911: if(fd != -1) { \
8912: _lseek(fd, 0, SEEK_END); \
8913: int size = _tell(fd); \
8914: _close(fd); \
8915: if(size == 0) { \
8916: remove(path); \
8917: } \
8918: } \
8919: }
8920:
8921: void msdos_finish()
8922: {
8923: for(int i = 0; i < MAX_FILES; i++) {
8924: if(file_handler[i].valid) {
8925: _close(i);
8926: }
8927: }
8928: #ifdef SUPPORT_AUX_PRN
8929: remove_std_file("stdaux.txt");
8930: remove_std_file("stdprn.txt");
8931: #endif
8932: msdos_dbcs_table_finish();
8933: }
8934:
8935: /* ----------------------------------------------------------------------------
8936: PC/AT hardware emulation
8937: ---------------------------------------------------------------------------- */
8938:
8939: void hardware_init()
8940: {
1.1.1.3 root 8941: CPU_INIT_CALL(CPU_MODEL);
1.1 root 8942: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 8943: m_IF = 1;
1.1.1.3 root 8944: #if defined(HAS_I386)
1.1 root 8945: cpu_type = (REG32(EDX) >> 8) & 0x0f;
8946: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 8947: #endif
8948: i386_set_a20_line(0);
1.1.1.14 root 8949:
1.1.1.19 root 8950: ems_init();
1.1 root 8951: pic_init();
1.1.1.8 root 8952: #ifdef PIT_ALWAYS_RUNNING
8953: pit_init();
8954: #else
1.1 root 8955: pit_active = 0;
8956: #endif
1.1.1.8 root 8957: cmos_init();
8958: kbd_init();
1.1 root 8959: }
8960:
1.1.1.10 root 8961: void hardware_finish()
8962: {
8963: #if defined(HAS_I386)
8964: vtlb_free(m_vtlb);
8965: #endif
1.1.1.19 root 8966: ems_finish();
1.1.1.10 root 8967: }
8968:
1.1 root 8969: void hardware_run()
8970: {
8971: int ops = 0;
8972:
1.1.1.3 root 8973: while(!m_halted) {
1.1 root 8974: #ifdef SUPPORT_DISASSEMBLER
8975: if(dasm) {
8976: char buffer[256];
1.1.1.3 root 8977: #if defined(HAS_I386)
1.1.1.19 root 8978: UINT32 eip = m_eip;
1.1.1.3 root 8979: #else
1.1.1.19 root 8980: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 8981: #endif
8982: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 8983:
1.1.1.3 root 8984: #if defined(HAS_I386)
8985: if(m_operand_size) {
1.1 root 8986: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 8987: } else
8988: #endif
8989: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.12 root 8990: fprintf(stderr, "%04x:%04x\t%s\n", SREG(CS), (unsigned)eip, buffer);
1.1 root 8991: }
8992: #endif
1.1.1.3 root 8993: #if defined(HAS_I386)
8994: m_cycles = 1;
1.1 root 8995: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 8996: #else
8997: CPU_EXECUTE_CALL(CPU_MODEL);
8998: #endif
1.1.1.14 root 8999: #if defined(HAS_I386)
9000: if(m_eip != m_prev_eip) {
9001: #else
9002: if(m_pc != m_prevpc) {
9003: #endif
9004: iops++;
9005: }
1.1.1.8 root 9006: if(++ops == 16384) {
1.1 root 9007: hardware_update();
9008: ops = 0;
9009: }
9010: }
9011: }
9012:
9013: void hardware_update()
9014: {
1.1.1.8 root 9015: static UINT32 prev_time = 0;
9016: UINT32 cur_time = timeGetTime();
9017:
9018: if(prev_time != cur_time) {
9019: // update pit and raise irq0
9020: #ifndef PIT_ALWAYS_RUNNING
9021: if(pit_active)
9022: #endif
9023: {
9024: if(pit_run(0, cur_time)) {
9025: pic_req(0, 0, 1);
9026: }
9027: pit_run(1, cur_time);
9028: pit_run(2, cur_time);
9029: }
9030: // check key input and raise irq1
1.1.1.14 root 9031: static UINT32 prev_tick = 0;
9032: UINT32 cur_tick = cur_time / 32;
9033: if(prev_tick != cur_tick) {
9034: // update keyboard flags
9035: UINT8 state;
9036: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
9037: state |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
9038: state |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
9039: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
9040: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
9041: state |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
9042: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
9043: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
9044: mem[0x417] = state;
9045: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
9046: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
9047: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
9048: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
9049: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
9050: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
9051: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
9052: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
9053: mem[0x418] = state;
9054:
9055: // update keyboard input
1.1.1.8 root 9056: if(check_key_input()) {
9057: pic_req(0, 1, 1);
9058: }
1.1.1.14 root 9059: prev_tick = cur_tick;
1.1.1.8 root 9060: }
1.1.1.19 root 9061: // update daily timer counter
9062: pcbios_update_daily_timer_counter(cur_time);
1.1.1.8 root 9063: prev_time = cur_time;
1.1 root 9064: }
9065: }
9066:
1.1.1.19 root 9067: // ems
9068:
9069: void ems_init()
9070: {
9071: memset(ems_handles, 0, sizeof(ems_handles));
9072: memset(ems_pages, 0, sizeof(ems_pages));
9073: free_ems_pages = MAX_EMS_PAGES;
9074: }
9075:
9076: void ems_finish()
9077: {
9078: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9079: if(ems_handles[i].buffer) {
9080: free(ems_handles[i].buffer);
9081: ems_handles[i].buffer = NULL;
9082: }
9083: }
9084: }
9085:
9086: void ems_allocate_pages(int handle, int pages)
9087: {
9088: if(pages > 0) {
9089: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
9090: } else {
9091: ems_handles[handle].buffer = NULL;
9092: }
9093: ems_handles[handle].pages = pages;
9094: ems_handles[handle].allocated = true;
9095: free_ems_pages -= pages;
9096: }
9097:
9098: void ems_reallocate_pages(int handle, int pages)
9099: {
9100: if(ems_handles[handle].allocated) {
9101: if(ems_handles[handle].pages != pages) {
9102: UINT8 *new_buffer = NULL;
9103:
9104: if(pages > 0) {
9105: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
9106: }
9107: if(ems_handles[handle].buffer) {
9108: if(new_buffer) {
9109: if(pages > ems_handles[handle].pages) {
9110: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
9111: } else {
9112: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
9113: }
9114: }
9115: free(ems_handles[handle].buffer);
9116: ems_handles[handle].buffer = NULL;
9117: }
9118: free_ems_pages += ems_handles[handle].pages;
9119:
9120: ems_handles[handle].buffer = new_buffer;
9121: ems_handles[handle].pages = pages;
9122: free_ems_pages -= pages;
9123: }
9124: } else {
9125: ems_allocate_pages(handle, pages);
9126: }
9127: }
9128:
9129: void ems_release_pages(int handle)
9130: {
9131: if(ems_handles[handle].allocated) {
9132: if(ems_handles[handle].buffer) {
9133: free(ems_handles[handle].buffer);
9134: ems_handles[handle].buffer = NULL;
9135: }
9136: free_ems_pages += ems_handles[handle].pages;
9137: ems_handles[handle].allocated = false;
9138: }
9139: }
9140:
9141: void ems_map_page(int physical, int handle, int logical)
9142: {
9143: if(ems_pages[physical].mapped) {
9144: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
9145: return;
9146: }
9147: ems_unmap_page(physical);
9148: }
9149: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
9150: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
9151: }
9152: ems_pages[physical].handle = handle;
9153: ems_pages[physical].page = logical;
9154: ems_pages[physical].mapped = true;
9155: }
9156:
9157: void ems_unmap_page(int physical)
9158: {
9159: if(ems_pages[physical].mapped) {
9160: int handle = ems_pages[physical].handle;
9161: int logical = ems_pages[physical].page;
9162:
9163: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
9164: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
9165: }
9166: ems_pages[physical].mapped = false;
9167: }
9168: }
9169:
1.1 root 9170: // pic
9171:
9172: void pic_init()
9173: {
1.1.1.8 root 9174: memset(pic, 0, sizeof(pic));
9175: pic[0].imr = pic[1].imr = 0xff;
1.1 root 9176:
9177: // from bochs bios
9178: pic_write(0, 0, 0x11); // icw1 = 11h
9179: pic_write(0, 1, 0x08); // icw2 = 08h
9180: pic_write(0, 1, 0x04); // icw3 = 04h
9181: pic_write(0, 1, 0x01); // icw4 = 01h
9182: pic_write(0, 1, 0xb8); // ocw1 = b8h
9183: pic_write(1, 0, 0x11); // icw1 = 11h
9184: pic_write(1, 1, 0x70); // icw2 = 70h
9185: pic_write(1, 1, 0x02); // icw3 = 02h
9186: pic_write(1, 1, 0x01); // icw4 = 01h
9187: }
9188:
9189: void pic_write(int c, UINT32 addr, UINT8 data)
9190: {
9191: if(addr & 1) {
9192: if(pic[c].icw2_r) {
9193: // icw2
9194: pic[c].icw2 = data;
9195: pic[c].icw2_r = 0;
9196: } else if(pic[c].icw3_r) {
9197: // icw3
9198: pic[c].icw3 = data;
9199: pic[c].icw3_r = 0;
9200: } else if(pic[c].icw4_r) {
9201: // icw4
9202: pic[c].icw4 = data;
9203: pic[c].icw4_r = 0;
9204: } else {
9205: // ocw1
9206: pic[c].imr = data;
9207: }
9208: } else {
9209: if(data & 0x10) {
9210: // icw1
9211: pic[c].icw1 = data;
9212: pic[c].icw2_r = 1;
9213: pic[c].icw3_r = (data & 2) ? 0 : 1;
9214: pic[c].icw4_r = data & 1;
9215: pic[c].irr = 0;
9216: pic[c].isr = 0;
9217: pic[c].imr = 0;
9218: pic[c].prio = 0;
9219: if(!(pic[c].icw1 & 1)) {
9220: pic[c].icw4 = 0;
9221: }
9222: pic[c].ocw3 = 0;
9223: } else if(data & 8) {
9224: // ocw3
9225: if(!(data & 2)) {
9226: data = (data & ~1) | (pic[c].ocw3 & 1);
9227: }
9228: if(!(data & 0x40)) {
9229: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
9230: }
9231: pic[c].ocw3 = data;
9232: } else {
9233: // ocw2
9234: int level = 0;
9235: if(data & 0x40) {
9236: level = data & 7;
9237: } else {
9238: if(!pic[c].isr) {
9239: return;
9240: }
9241: level = pic[c].prio;
9242: while(!(pic[c].isr & (1 << level))) {
9243: level = (level + 1) & 7;
9244: }
9245: }
9246: if(data & 0x80) {
9247: pic[c].prio = (level + 1) & 7;
9248: }
9249: if(data & 0x20) {
9250: pic[c].isr &= ~(1 << level);
9251: }
9252: }
9253: }
9254: pic_update();
9255: }
9256:
9257: UINT8 pic_read(int c, UINT32 addr)
9258: {
9259: if(addr & 1) {
9260: return(pic[c].imr);
9261: } else {
9262: // polling mode is not supported...
9263: //if(pic[c].ocw3 & 4) {
9264: // return ???;
9265: //}
9266: if(pic[c].ocw3 & 1) {
9267: return(pic[c].isr);
9268: } else {
9269: return(pic[c].irr);
9270: }
9271: }
9272: }
9273:
9274: void pic_req(int c, int level, int signal)
9275: {
9276: if(signal) {
9277: pic[c].irr |= (1 << level);
9278: } else {
9279: pic[c].irr &= ~(1 << level);
9280: }
9281: pic_update();
9282: }
9283:
9284: int pic_ack()
9285: {
9286: // ack (INTA=L)
9287: pic[pic_req_chip].isr |= pic_req_bit;
9288: pic[pic_req_chip].irr &= ~pic_req_bit;
9289: if(pic_req_chip > 0) {
9290: // update isr and irr of master
9291: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
9292: pic[pic_req_chip - 1].isr |= slave;
9293: pic[pic_req_chip - 1].irr &= ~slave;
9294: }
9295: //if(pic[pic_req_chip].icw4 & 1) {
9296: // 8086 mode
9297: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
9298: //} else {
9299: // // 8080 mode
9300: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
9301: // if(pic[pic_req_chip].icw1 & 4) {
9302: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
9303: // } else {
9304: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
9305: // }
9306: // vector = 0xcd | (addr << 8);
9307: //}
9308: if(pic[pic_req_chip].icw4 & 2) {
9309: // auto eoi
9310: pic[pic_req_chip].isr &= ~pic_req_bit;
9311: }
9312: return(vector);
9313: }
9314:
9315: void pic_update()
9316: {
9317: for(int c = 0; c < 2; c++) {
9318: UINT8 irr = pic[c].irr;
9319: if(c + 1 < 2) {
9320: // this is master
9321: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
9322: // request from slave
9323: irr |= 1 << (pic[c + 1].icw3 & 7);
9324: }
9325: }
9326: irr &= (~pic[c].imr);
9327: if(!irr) {
9328: break;
9329: }
9330: if(!(pic[c].ocw3 & 0x20)) {
9331: irr |= pic[c].isr;
9332: }
9333: int level = pic[c].prio;
9334: UINT8 bit = 1 << level;
9335: while(!(irr & bit)) {
9336: level = (level + 1) & 7;
9337: bit = 1 << level;
9338: }
9339: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
9340: // check slave
9341: continue;
9342: }
9343: if(pic[c].isr & bit) {
9344: break;
9345: }
9346: // interrupt request
9347: pic_req_chip = c;
9348: pic_req_level = level;
9349: pic_req_bit = bit;
1.1.1.3 root 9350: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 9351: return;
9352: }
1.1.1.3 root 9353: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 9354: }
1.1 root 9355:
9356: // pit
9357:
9358: #define PIT_FREQ 1193182
9359: #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)
9360:
9361: void pit_init()
9362: {
1.1.1.8 root 9363: memset(pit, 0, sizeof(pit));
1.1 root 9364: for(int ch = 0; ch < 3; ch++) {
9365: pit[ch].count = 0x10000;
9366: pit[ch].ctrl_reg = 0x34;
9367: pit[ch].mode = 3;
9368: }
9369:
9370: // from bochs bios
9371: pit_write(3, 0x34);
9372: pit_write(0, 0x00);
9373: pit_write(0, 0x00);
9374: }
9375:
9376: void pit_write(int ch, UINT8 val)
9377: {
1.1.1.8 root 9378: #ifndef PIT_ALWAYS_RUNNING
1.1 root 9379: if(!pit_active) {
9380: pit_active = 1;
9381: pit_init();
9382: }
1.1.1.8 root 9383: #endif
1.1 root 9384: switch(ch) {
9385: case 0:
9386: case 1:
9387: case 2:
9388: // write count register
9389: if(!pit[ch].low_write && !pit[ch].high_write) {
9390: if(pit[ch].ctrl_reg & 0x10) {
9391: pit[ch].low_write = 1;
9392: }
9393: if(pit[ch].ctrl_reg & 0x20) {
9394: pit[ch].high_write = 1;
9395: }
9396: }
9397: if(pit[ch].low_write) {
9398: pit[ch].count_reg = val;
9399: pit[ch].low_write = 0;
9400: } else if(pit[ch].high_write) {
9401: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
9402: pit[ch].count_reg = val << 8;
9403: } else {
9404: pit[ch].count_reg |= val << 8;
9405: }
9406: pit[ch].high_write = 0;
9407: }
9408: // start count
1.1.1.8 root 9409: if(!pit[ch].low_write && !pit[ch].high_write) {
9410: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
9411: pit[ch].count = PIT_COUNT_VALUE(ch);
9412: pit[ch].prev_time = timeGetTime();
9413: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 9414: }
9415: }
9416: break;
9417: case 3: // ctrl reg
9418: if((val & 0xc0) == 0xc0) {
9419: // i8254 read-back command
9420: for(ch = 0; ch < 3; ch++) {
9421: if(!(val & 0x10) && !pit[ch].status_latched) {
9422: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
9423: pit[ch].status_latched = 1;
9424: }
9425: if(!(val & 0x20) && !pit[ch].count_latched) {
9426: pit_latch_count(ch);
9427: }
9428: }
9429: break;
9430: }
9431: ch = (val >> 6) & 3;
9432: if(val & 0x30) {
9433: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
9434: pit[ch].mode = modes[(val >> 1) & 7];
9435: pit[ch].count_latched = 0;
9436: pit[ch].low_read = pit[ch].high_read = 0;
9437: pit[ch].low_write = pit[ch].high_write = 0;
9438: pit[ch].ctrl_reg = val;
9439: // stop count
1.1.1.8 root 9440: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 9441: pit[ch].count_reg = 0;
9442: } else if(!pit[ch].count_latched) {
9443: pit_latch_count(ch);
9444: }
9445: break;
9446: }
9447: }
9448:
9449: UINT8 pit_read(int ch)
9450: {
1.1.1.8 root 9451: #ifndef PIT_ALWAYS_RUNNING
1.1 root 9452: if(!pit_active) {
9453: pit_active = 1;
9454: pit_init();
9455: }
1.1.1.8 root 9456: #endif
1.1 root 9457: switch(ch) {
9458: case 0:
9459: case 1:
9460: case 2:
9461: if(pit[ch].status_latched) {
9462: pit[ch].status_latched = 0;
9463: return(pit[ch].status);
9464: }
9465: // if not latched, through current count
9466: if(!pit[ch].count_latched) {
9467: if(!pit[ch].low_read && !pit[ch].high_read) {
9468: pit_latch_count(ch);
9469: }
9470: }
9471: // return latched count
9472: if(pit[ch].low_read) {
9473: pit[ch].low_read = 0;
9474: if(!pit[ch].high_read) {
9475: pit[ch].count_latched = 0;
9476: }
9477: return(pit[ch].latch & 0xff);
9478: } else if(pit[ch].high_read) {
9479: pit[ch].high_read = 0;
9480: pit[ch].count_latched = 0;
9481: return((pit[ch].latch >> 8) & 0xff);
9482: }
9483: }
9484: return(0xff);
9485: }
9486:
1.1.1.8 root 9487: int pit_run(int ch, UINT32 cur_time)
1.1 root 9488: {
1.1.1.8 root 9489: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 9490: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 9491: pit[ch].prev_time = pit[ch].expired_time;
9492: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
9493: if(cur_time >= pit[ch].expired_time) {
9494: pit[ch].prev_time = cur_time;
9495: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 9496: }
1.1.1.8 root 9497: return(1);
1.1 root 9498: }
1.1.1.8 root 9499: return(0);
1.1 root 9500: }
9501:
9502: void pit_latch_count(int ch)
9503: {
1.1.1.8 root 9504: UINT32 cur_time = timeGetTime();
9505:
9506: if(pit[ch].expired_time != 0) {
9507: pit_run(ch, cur_time);
9508: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
9509: pit[ch].latch = (tmp != 0) ? (UINT16)tmp : 1;
9510: } else {
9511: pit[ch].latch = (UINT16)pit[ch].count;
1.1 root 9512: }
9513: pit[ch].count_latched = 1;
9514: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
9515: // lower byte
9516: pit[ch].low_read = 1;
9517: pit[ch].high_read = 0;
9518: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
9519: // upper byte
9520: pit[ch].low_read = 0;
9521: pit[ch].high_read = 1;
9522: } else {
9523: // lower -> upper
1.1.1.14 root 9524: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 9525: }
9526: }
9527:
1.1.1.8 root 9528: int pit_get_expired_time(int ch)
1.1 root 9529: {
1.1.1.8 root 9530: UINT32 val = (1000 * pit[ch].count) / PIT_FREQ;
9531: return((val > 0) ? val : 1);
9532: }
9533:
9534: // cmos
9535:
9536: void cmos_init()
9537: {
9538: memset(cmos, 0, sizeof(cmos));
9539: cmos_addr = 0;
1.1 root 9540:
1.1.1.8 root 9541: // from DOSBox
9542: cmos_write(0x0a, 0x26);
9543: cmos_write(0x0b, 0x02);
9544: cmos_write(0x0d, 0x80);
1.1 root 9545: }
9546:
1.1.1.8 root 9547: void cmos_write(int addr, UINT8 val)
1.1 root 9548: {
1.1.1.8 root 9549: cmos[addr & 0x7f] = val;
9550: }
9551:
9552: #define CMOS_GET_TIME() { \
9553: UINT32 cur_sec = timeGetTime() / 1000 ; \
9554: if(prev_sec != cur_sec) { \
9555: GetLocalTime(&time); \
9556: prev_sec = cur_sec; \
9557: } \
1.1 root 9558: }
1.1.1.8 root 9559: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 9560:
1.1.1.8 root 9561: UINT8 cmos_read(int addr)
1.1 root 9562: {
1.1.1.8 root 9563: static SYSTEMTIME time;
9564: static UINT32 prev_sec = 0;
1.1 root 9565:
1.1.1.8 root 9566: switch(addr & 0x7f) {
9567: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
9568: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
9569: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
9570: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
9571: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
9572: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
9573: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
9574: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
9575: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
9576: case 0x15: return((MEMORY_END >> 10) & 0xff);
9577: case 0x16: return((MEMORY_END >> 18) & 0xff);
9578: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
9579: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
9580: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
9581: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
9582: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 9583: }
1.1.1.8 root 9584: return(cmos[addr & 0x7f]);
1.1 root 9585: }
9586:
1.1.1.7 root 9587: // kbd (a20)
9588:
9589: void kbd_init()
9590: {
1.1.1.8 root 9591: kbd_data = kbd_command = 0;
1.1.1.7 root 9592: kbd_status = 0x18;
9593: }
9594:
9595: UINT8 kbd_read_data()
9596: {
1.1.1.8 root 9597: kbd_status &= ~1;
1.1.1.7 root 9598: return(kbd_data);
9599: }
9600:
9601: void kbd_write_data(UINT8 val)
9602: {
9603: switch(kbd_command) {
9604: case 0xd1:
9605: i386_set_a20_line((val >> 1) & 1);
9606: break;
9607: }
9608: kbd_command = 0;
1.1.1.8 root 9609: kbd_status &= ~8;
1.1.1.7 root 9610: }
9611:
9612: UINT8 kbd_read_status()
9613: {
9614: return(kbd_status);
9615: }
9616:
9617: void kbd_write_command(UINT8 val)
9618: {
9619: switch(val) {
9620: case 0xd0:
9621: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 9622: kbd_status |= 1;
1.1.1.7 root 9623: break;
9624: case 0xdd:
9625: i386_set_a20_line(0);
9626: break;
9627: case 0xdf:
9628: i386_set_a20_line(1);
9629: break;
9630: case 0xf0:
9631: case 0xf1:
9632: case 0xf2:
9633: case 0xf3:
9634: case 0xf4:
9635: case 0xf5:
9636: case 0xf6:
9637: case 0xf7:
9638: case 0xf8:
9639: case 0xf9:
9640: case 0xfa:
9641: case 0xfb:
9642: case 0xfc:
9643: case 0xfd:
9644: case 0xfe:
9645: case 0xff:
9646: if(!(val & 1)) {
1.1.1.8 root 9647: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 9648: // reset pic
9649: pic_init();
9650: pic[0].irr = pic[1].irr = 0x00;
9651: pic[0].imr = pic[1].imr = 0xff;
9652: }
9653: CPU_RESET_CALL(CPU_MODEL);
9654: i386_jmp_far(0x40, 0x67);
9655: }
9656: i386_set_a20_line((val >> 1) & 1);
9657: break;
9658: }
9659: kbd_command = val;
1.1.1.8 root 9660: kbd_status |= 8;
1.1.1.7 root 9661: }
9662:
1.1.1.9 root 9663: // vga
9664:
9665: UINT8 vga_read_status()
9666: {
9667: // 60hz
9668: static const int period[3] = {16, 17, 17};
9669: static int index = 0;
9670: UINT32 time = timeGetTime() % period[index];
9671:
9672: index = (index + 1) % 3;
1.1.1.14 root 9673: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 9674: }
9675:
1.1 root 9676: // i/o bus
9677:
9678: UINT8 read_io_byte(offs_t addr)
9679: {
9680: switch(addr) {
9681: case 0x20:
9682: case 0x21:
9683: return(pic_read(0, addr));
9684: case 0x40:
9685: case 0x41:
9686: case 0x42:
9687: case 0x43:
9688: return(pit_read(addr & 0x03));
1.1.1.7 root 9689: case 0x60:
9690: return(kbd_read_data());
1.1.1.9 root 9691: case 0x61:
9692: return(system_port);
1.1.1.7 root 9693: case 0x64:
9694: return(kbd_read_status());
1.1 root 9695: case 0x71:
1.1.1.8 root 9696: return(cmos_read(cmos_addr));
1.1 root 9697: case 0x92:
1.1.1.3 root 9698: return((m_a20_mask >> 19) & 2);
1.1 root 9699: case 0xa0:
9700: case 0xa1:
9701: return(pic_read(1, addr));
1.1.1.9 root 9702: case 0x3ba:
9703: case 0x3da:
9704: return(vga_read_status());
1.1 root 9705: default:
9706: // error("inb %4x\n", addr);
9707: break;
9708: }
9709: return(0xff);
9710: }
9711:
9712: UINT16 read_io_word(offs_t addr)
9713: {
9714: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
9715: }
9716:
9717: UINT32 read_io_dword(offs_t addr)
9718: {
9719: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
9720: }
9721:
9722: void write_io_byte(offs_t addr, UINT8 val)
9723: {
9724: switch(addr) {
9725: case 0x20:
9726: case 0x21:
9727: pic_write(0, addr, val);
9728: break;
9729: case 0x40:
9730: case 0x41:
9731: case 0x42:
9732: case 0x43:
9733: pit_write(addr & 0x03, val);
9734: break;
1.1.1.7 root 9735: case 0x60:
9736: kbd_write_data(val);
9737: break;
1.1.1.9 root 9738: case 0x61:
9739: if((system_port & 3) != 3 && (val & 3) == 3) {
9740: // beep on
9741: // MessageBeep(-1);
9742: } else if((system_port & 3) == 3 && (val & 3) != 3) {
9743: // beep off
9744: }
9745: system_port = val;
9746: break;
1.1 root 9747: case 0x64:
1.1.1.7 root 9748: kbd_write_command(val);
1.1 root 9749: break;
9750: case 0x70:
9751: cmos_addr = val;
9752: break;
9753: case 0x71:
1.1.1.8 root 9754: cmos_write(cmos_addr, val);
1.1 root 9755: break;
9756: case 0x92:
1.1.1.7 root 9757: i386_set_a20_line((val >> 1) & 1);
1.1 root 9758: break;
9759: case 0xa0:
9760: case 0xa1:
9761: pic_write(1, addr, val);
9762: break;
9763: default:
9764: // error("outb %4x,%2x\n", addr, val);
9765: break;
9766: }
9767: }
9768:
9769: void write_io_word(offs_t addr, UINT16 val)
9770: {
9771: write_io_byte(addr + 0, (val >> 0) & 0xff);
9772: write_io_byte(addr + 1, (val >> 8) & 0xff);
9773: }
9774:
9775: void write_io_dword(offs_t addr, UINT32 val)
9776: {
9777: write_io_byte(addr + 0, (val >> 0) & 0xff);
9778: write_io_byte(addr + 1, (val >> 8) & 0xff);
9779: write_io_byte(addr + 2, (val >> 16) & 0xff);
9780: write_io_byte(addr + 3, (val >> 24) & 0xff);
9781: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.