|
|
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:
1.1.1.28 root 10: void exit_handler();
11:
1.1 root 12: #define fatalerror(...) { \
13: fprintf(stderr, __VA_ARGS__); \
1.1.1.28 root 14: exit_handler(); \
1.1 root 15: exit(1); \
16: }
17: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
1.1.1.22 root 18: #define nolog(...)
19:
20: //#define ENABLE_DEBUG
21: #ifdef ENABLE_DEBUG
22: #define EXPORT_DEBUG_TO_FILE
23: #define ENABLE_DEBUG_DASM
24: #define ENABLE_DEBUG_SYSCALL
25: #define ENABLE_DEBUG_UNIMPLEMENTED
1.1.1.25 root 26: #define ENABLE_DEBUG_IOPORT
1.1.1.22 root 27:
28: #ifdef EXPORT_DEBUG_TO_FILE
29: FILE* fdebug = NULL;
30: #else
31: #define fdebug stderr
32: #endif
33: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
34: #define unimplemented_10h fatalerror
1.1.1.25 root 35: #define unimplemented_14h fatalerror
1.1.1.22 root 36: #define unimplemented_15h fatalerror
37: #define unimplemented_16h fatalerror
38: #define unimplemented_1ah fatalerror
39: #define unimplemented_21h fatalerror
40: #define unimplemented_2fh fatalerror
1.1.1.24 root 41: #define unimplemented_33h fatalerror
1.1.1.22 root 42: #define unimplemented_67h fatalerror
43: #define unimplemented_xms fatalerror
44: #endif
45: #endif
46: #ifndef unimplemented_10h
47: #define unimplemented_10h nolog
48: #endif
1.1.1.25 root 49: #ifndef unimplemented_14h
50: #define unimplemented_14h nolog
51: #endif
1.1.1.22 root 52: #ifndef unimplemented_15h
53: #define unimplemented_15h nolog
54: #endif
55: #ifndef unimplemented_16h
56: #define unimplemented_16h nolog
57: #endif
58: #ifndef unimplemented_1ah
59: #define unimplemented_1ah nolog
60: #endif
61: #ifndef unimplemented_21h
62: #define unimplemented_21h nolog
63: #endif
64: #ifndef unimplemented_2fh
65: #define unimplemented_2fh nolog
66: #endif
1.1.1.24 root 67: #ifndef unimplemented_33h
68: #define unimplemented_33h nolog
69: #endif
1.1.1.22 root 70: #ifndef unimplemented_67h
71: #define unimplemented_67h nolog
72: #endif
73: #ifndef unimplemented_xms
74: #define unimplemented_xms nolog
75: #endif
76:
1.1.1.32! root 77: #define array_length(array) (sizeof(array) / sizeof(array[0]))
1.1.1.22 root 78: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
79: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
80: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 81:
1.1.1.12 root 82: #if defined(__MINGW32__)
83: extern "C" int _CRT_glob = 0;
84: #endif
85:
86: /*
87: kludge for "more-standardized" C++
88: */
89: #if !defined(_MSC_VER)
90: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
91: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
92: #define min(a,b) kludge_min(a,b)
93: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 94: #elif _MSC_VER >= 1400
95: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
96: {
97: }
98: #endif
99:
100: #define USE_THREAD
101:
102: #ifdef USE_THREAD
103: static CRITICAL_SECTION vram_crit_sect;
104: #else
105: #define EnterCriticalSection(x)
106: #define LeaveCriticalSection(x)
107: #define vram_flush()
1.1.1.12 root 108: #endif
109:
1.1.1.14 root 110: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
111: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
112:
113: void change_console_size(int width, int height);
114: void clear_scr_buffer(WORD attr);
115:
116: static UINT32 vram_length_char = 0, vram_length_attr = 0;
117: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
118: static COORD vram_coord_char, vram_coord_attr;
119:
1.1.1.28 root 120: char temp_file_path[MAX_PATH];
121: bool temp_file_created = false;
122:
1.1.1.14 root 123: bool ignore_illegal_insn = false;
124: bool limit_max_memory = false;
125: bool no_windows = false;
126: //bool ctrl_break = false;
127: bool stay_busy = false;
128: UINT32 iops = 0;
1.1.1.19 root 129: bool support_ems = false;
130: #ifdef SUPPORT_XMS
131: bool support_xms = false;
132: #endif
1.1.1.29 root 133: int sio_port_number[4] = {0, 0, 0, 0};
1.1.1.14 root 134:
135: BOOL is_vista_or_later;
136:
137: inline void maybe_idle()
138: {
139: // if it appears to be in a tight loop, assume waiting for input
140: // allow for one updated video character, for a spinning cursor
141: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
142: Sleep(10);
143: }
144: iops = 0;
145: }
1.1.1.12 root 146:
1.1 root 147: /* ----------------------------------------------------------------------------
1.1.1.3 root 148: MAME i86/i386
1.1 root 149: ---------------------------------------------------------------------------- */
150:
1.1.1.10 root 151: #ifndef __BIG_ENDIAN__
1.1 root 152: #define LSB_FIRST
1.1.1.10 root 153: #endif
1.1 root 154:
155: #ifndef INLINE
156: #define INLINE inline
157: #endif
158: #define U64(v) UINT64(v)
159:
160: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
161: #define logerror(...)
162: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
163: #define popmessage(...)
164:
165: /*****************************************************************************/
1.1.1.10 root 166: /* src/emu/devcpu.h */
167:
168: // CPU interface functions
169: #define CPU_INIT_NAME(name) cpu_init_##name
170: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
171: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
172:
173: #define CPU_RESET_NAME(name) cpu_reset_##name
174: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
175: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
176:
177: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
178: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
179: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
180:
181: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
182: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
183: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
184:
185: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
186: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
187: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
188:
1.1.1.14 root 189: #define CPU_MODEL_STR(name) #name
190: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
191:
1.1.1.10 root 192: /*****************************************************************************/
193: /* src/emu/didisasm.h */
194:
195: // Disassembler constants
196: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
197: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
198: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
199: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
200: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
201: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
202:
203: /*****************************************************************************/
1.1 root 204: /* src/emu/diexec.h */
205:
206: // I/O line states
207: enum line_state
208: {
209: CLEAR_LINE = 0, // clear (a fired or held) line
210: ASSERT_LINE, // assert an interrupt immediately
211: HOLD_LINE, // hold interrupt line until acknowledged
212: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
213: };
214:
215: // I/O line definitions
216: enum
217: {
218: INPUT_LINE_IRQ = 0,
219: INPUT_LINE_NMI
220: };
221:
222: /*****************************************************************************/
1.1.1.10 root 223: /* src/emu/dimemory.h */
1.1 root 224:
1.1.1.10 root 225: // Translation intentions
226: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
227: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
228: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
229:
230: const int TRANSLATE_READ = 0; // translate for read
231: const int TRANSLATE_WRITE = 1; // translate for write
232: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
233: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
234: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
235: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
236: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
237: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
238: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 239:
1.1.1.10 root 240: /*****************************************************************************/
241: /* src/emu/emucore.h */
1.1 root 242:
1.1.1.10 root 243: // constants for expression endianness
244: enum endianness_t
245: {
246: ENDIANNESS_LITTLE,
247: ENDIANNESS_BIG
248: };
1.1 root 249:
1.1.1.10 root 250: // declare native endianness to be one or the other
251: #ifdef LSB_FIRST
252: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
253: #else
254: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
255: #endif
256:
257: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
258: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
259:
260: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
261: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
262:
263: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
264: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 265:
266: /*****************************************************************************/
267: /* src/emu/memory.h */
268:
1.1.1.10 root 269: // address spaces
270: enum address_spacenum
271: {
272: AS_0, // first address space
273: AS_1, // second address space
274: AS_2, // third address space
275: AS_3, // fourth address space
276: ADDRESS_SPACES, // maximum number of address spaces
277:
278: // alternate address space names for common use
279: AS_PROGRAM = AS_0, // program address space
280: AS_DATA = AS_1, // data address space
281: AS_IO = AS_2 // I/O address space
282: };
283:
1.1 root 284: // offsets and addresses are 32-bit (for now...)
1.1.1.30 root 285: //typedef UINT32 offs_t;
1.1 root 286:
287: // read accessors
288: UINT8 read_byte(offs_t byteaddress)
289: {
1.1.1.4 root 290: #if defined(HAS_I386)
1.1 root 291: if(byteaddress < MAX_MEM) {
292: return mem[byteaddress];
1.1.1.3 root 293: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
294: // return read_byte(byteaddress & 0xfffff);
1.1 root 295: }
296: return 0;
1.1.1.4 root 297: #else
298: return mem[byteaddress];
299: #endif
1.1 root 300: }
301:
302: UINT16 read_word(offs_t byteaddress)
303: {
1.1.1.14 root 304: if(byteaddress == 0x41c) {
305: // pointer to first free slot in keyboard buffer
306: // XXX: the buffer itself doesn't actually exist in DOS memory
1.1.1.32! root 307: if(key_buf_char != NULL) {
! 308: if(key_buf_char->count() == 0) {
! 309: maybe_idle();
! 310: }
! 311: return (UINT16)key_buf_char->count();
1.1.1.14 root 312: }
1.1.1.32! root 313: return 0;
1.1.1.14 root 314: }
1.1.1.4 root 315: #if defined(HAS_I386)
1.1 root 316: if(byteaddress < MAX_MEM - 1) {
317: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 318: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
319: // return read_word(byteaddress & 0xfffff);
1.1 root 320: }
321: return 0;
1.1.1.4 root 322: #else
323: return *(UINT16 *)(mem + byteaddress);
324: #endif
1.1 root 325: }
326:
327: UINT32 read_dword(offs_t byteaddress)
328: {
1.1.1.4 root 329: #if defined(HAS_I386)
1.1 root 330: if(byteaddress < MAX_MEM - 3) {
331: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 332: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
333: // return read_dword(byteaddress & 0xfffff);
1.1 root 334: }
335: return 0;
1.1.1.4 root 336: #else
337: return *(UINT32 *)(mem + byteaddress);
338: #endif
1.1 root 339: }
340:
341: // write accessors
1.1.1.14 root 342: #ifdef USE_THREAD
343: void vram_flush_char()
344: {
345: if(vram_length_char != 0) {
346: DWORD num;
1.1.1.23 root 347: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 348: vram_length_char = vram_last_length_char = 0;
349: }
350: }
351:
352: void vram_flush_attr()
353: {
354: if(vram_length_attr != 0) {
355: DWORD num;
1.1.1.23 root 356: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 357: vram_length_attr = vram_last_length_attr = 0;
358: }
359: }
360:
361: void vram_flush()
362: {
363: if(vram_length_char != 0 || vram_length_attr != 0) {
364: EnterCriticalSection(&vram_crit_sect);
365: vram_flush_char();
366: vram_flush_attr();
367: LeaveCriticalSection(&vram_crit_sect);
368: }
369: }
370: #endif
371:
372: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 373: {
1.1.1.14 root 374: #ifdef USE_THREAD
375: static offs_t first_offset_char, last_offset_char;
376:
377: if(vram_length_char != 0) {
378: if(offset <= last_offset_char && offset >= first_offset_char) {
379: scr_char[(offset - first_offset_char) >> 1] = data;
380: return;
381: }
382: if(offset != last_offset_char + 2) {
383: vram_flush_char();
384: }
385: }
386: if(vram_length_char == 0) {
387: first_offset_char = offset;
388: vram_coord_char.X = (offset >> 1) % scr_width;
389: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
390: }
391: scr_char[vram_length_char++] = data;
392: last_offset_char = offset;
393: #else
1.1.1.8 root 394: COORD co;
395: DWORD num;
396:
1.1.1.14 root 397: co.X = (offset >> 1) % scr_width;
398: co.Y = (offset >> 1) / scr_width;
399: scr_char[0] = data;
1.1.1.23 root 400: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 401: #endif
402: }
403:
404: void write_text_vram_attr(offs_t offset, UINT8 data)
405: {
406: #ifdef USE_THREAD
407: static offs_t first_offset_attr, last_offset_attr;
408:
409: if(vram_length_attr != 0) {
410: if(offset <= last_offset_attr && offset >= first_offset_attr) {
411: scr_attr[(offset - first_offset_attr) >> 1] = data;
412: return;
413: }
414: if(offset != last_offset_attr + 2) {
415: vram_flush_attr();
416: }
417: }
418: if(vram_length_attr == 0) {
419: first_offset_attr = offset;
420: vram_coord_attr.X = (offset >> 1) % scr_width;
421: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
422: }
423: scr_attr[vram_length_attr++] = data;
424: last_offset_attr = offset;
425: #else
426: COORD co;
427: DWORD num;
1.1.1.8 root 428:
1.1.1.14 root 429: co.X = (offset >> 1) % scr_width;
430: co.Y = (offset >> 1) / scr_width;
431: scr_attr[0] = data;
1.1.1.23 root 432: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 433: #endif
434: }
435:
436: void write_text_vram_byte(offs_t offset, UINT8 data)
437: {
438: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 439: if(offset & 1) {
1.1.1.14 root 440: write_text_vram_attr(offset, data);
1.1.1.8 root 441: } else {
1.1.1.14 root 442: write_text_vram_char(offset, data);
1.1.1.8 root 443: }
1.1.1.14 root 444: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 445: }
446:
447: void write_text_vram_word(offs_t offset, UINT16 data)
448: {
1.1.1.14 root 449: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 450: if(offset & 1) {
1.1.1.14 root 451: write_text_vram_attr(offset , (data ) & 0xff);
452: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 453: } else {
1.1.1.14 root 454: write_text_vram_char(offset , (data ) & 0xff);
455: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 456: }
1.1.1.14 root 457: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 458: }
459:
460: void write_text_vram_dword(offs_t offset, UINT32 data)
461: {
1.1.1.14 root 462: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 463: if(offset & 1) {
1.1.1.14 root 464: write_text_vram_attr(offset , (data ) & 0xff);
465: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
466: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
467: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
468: } else {
469: write_text_vram_char(offset , (data ) & 0xff);
470: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
471: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
472: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 473: }
1.1.1.14 root 474: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 475: }
476:
1.1 root 477: void write_byte(offs_t byteaddress, UINT8 data)
478: {
1.1.1.8 root 479: if(byteaddress < MEMORY_END) {
1.1.1.3 root 480: mem[byteaddress] = data;
1.1.1.8 root 481: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 482: if(!restore_console_on_exit) {
483: change_console_size(scr_width, scr_height);
1.1.1.12 root 484: }
1.1.1.8 root 485: write_text_vram_byte(byteaddress - text_vram_top_address, data);
486: mem[byteaddress] = data;
487: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
488: if(int_10h_feh_called && !int_10h_ffh_called) {
489: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 490: }
491: mem[byteaddress] = data;
1.1.1.4 root 492: #if defined(HAS_I386)
1.1.1.3 root 493: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 494: #else
495: } else {
496: #endif
1.1.1.3 root 497: mem[byteaddress] = data;
1.1 root 498: }
499: }
500:
501: void write_word(offs_t byteaddress, UINT16 data)
502: {
1.1.1.8 root 503: if(byteaddress < MEMORY_END) {
1.1.1.14 root 504: if(byteaddress == 0x450 + mem[0x462] * 2) {
505: COORD co;
506: co.X = data & 0xff;
507: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 508: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 509: }
1.1.1.3 root 510: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 511: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 512: if(!restore_console_on_exit) {
513: change_console_size(scr_width, scr_height);
1.1.1.12 root 514: }
1.1.1.8 root 515: write_text_vram_word(byteaddress - text_vram_top_address, data);
516: *(UINT16 *)(mem + byteaddress) = data;
517: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
518: if(int_10h_feh_called && !int_10h_ffh_called) {
519: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 520: }
521: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 522: #if defined(HAS_I386)
1.1.1.3 root 523: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 524: #else
525: } else {
526: #endif
1.1.1.3 root 527: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 528: }
529: }
530:
531: void write_dword(offs_t byteaddress, UINT32 data)
532: {
1.1.1.8 root 533: if(byteaddress < MEMORY_END) {
1.1.1.3 root 534: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 535: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 536: if(!restore_console_on_exit) {
537: change_console_size(scr_width, scr_height);
1.1.1.12 root 538: }
1.1.1.8 root 539: write_text_vram_dword(byteaddress - text_vram_top_address, data);
540: *(UINT32 *)(mem + byteaddress) = data;
541: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
542: if(int_10h_feh_called && !int_10h_ffh_called) {
543: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 544: }
545: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 546: #if defined(HAS_I386)
1.1.1.3 root 547: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 548: #else
549: } else {
550: #endif
1.1.1.3 root 551: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 552: }
553: }
554:
555: #define read_decrypted_byte read_byte
556: #define read_decrypted_word read_word
557: #define read_decrypted_dword read_dword
558:
1.1.1.3 root 559: #define read_raw_byte read_byte
560: #define write_raw_byte write_byte
561:
562: #define read_word_unaligned read_word
563: #define write_word_unaligned write_word
564:
565: #define read_io_word_unaligned read_io_word
566: #define write_io_word_unaligned write_io_word
567:
1.1 root 568: UINT8 read_io_byte(offs_t byteaddress);
569: UINT16 read_io_word(offs_t byteaddress);
570: UINT32 read_io_dword(offs_t byteaddress);
571:
572: void write_io_byte(offs_t byteaddress, UINT8 data);
573: void write_io_word(offs_t byteaddress, UINT16 data);
574: void write_io_dword(offs_t byteaddress, UINT32 data);
575:
576: /*****************************************************************************/
577: /* src/osd/osdcomm.h */
578:
579: /* Highly useful macro for compile-time knowledge of an array size */
580: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
581:
1.1.1.3 root 582: #if defined(HAS_I386)
1.1.1.10 root 583: static CPU_TRANSLATE(i386);
584: #include "mame/lib/softfloat/softfloat.c"
585: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 586: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 587: #elif defined(HAS_I286)
1.1.1.10 root 588: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 589: #else
1.1.1.10 root 590: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 591: #endif
1.1.1.22 root 592: #ifdef ENABLE_DEBUG_DASM
1.1.1.10 root 593: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.22 root 594: int dasm = 0;
1.1 root 595: #endif
596:
1.1.1.3 root 597: #if defined(HAS_I386)
598: #define SREG(x) m_sreg[x].selector
599: #define SREG_BASE(x) m_sreg[x].base
600:
601: int cpu_type, cpu_step;
602: #else
603: #define REG8(x) m_regs.b[x]
604: #define REG16(x) m_regs.w[x]
605: #define SREG(x) m_sregs[x]
606: #define SREG_BASE(x) m_base[x]
607: #define m_CF m_CarryVal
608: #define m_a20_mask AMASK
609: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
610: #if defined(HAS_I286)
611: #define i386_set_a20_line(x) i80286_set_a20_line(x)
612: #else
613: #define i386_set_a20_line(x)
614: #endif
615: #define i386_set_irq_line(x, y) set_irq_line(x, y)
616: #endif
1.1 root 617:
618: void i386_jmp_far(UINT16 selector, UINT32 address)
619: {
1.1.1.3 root 620: #if defined(HAS_I386)
1.1 root 621: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 622: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 623: } else {
1.1.1.3 root 624: SREG(CS) = selector;
625: m_performed_intersegment_jump = 1;
626: i386_load_segment_descriptor(CS);
627: m_eip = address;
628: CHANGE_PC(m_eip);
1.1 root 629: }
1.1.1.3 root 630: #elif defined(HAS_I286)
631: i80286_code_descriptor(selector, address, 1);
632: #else
633: SREG(CS) = selector;
634: i386_load_segment_descriptor(CS);
635: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
636: #endif
1.1 root 637: }
638:
1.1.1.24 root 639: /*
640: void i386_call_far(UINT16 selector, UINT32 address)
641: {
642: #if defined(HAS_I386)
643: if(PROTECTED_MODE && !V8086_MODE) {
644: i386_protected_mode_call(selector, address, 1, m_operand_size);
645: } else {
646: PUSH16(SREG(CS));
647: PUSH16(m_eip);
648: SREG(CS) = selector;
649: m_performed_intersegment_jump = 1;
650: i386_load_segment_descriptor(CS);
651: m_eip = address;
652: CHANGE_PC(m_eip);
653: }
654: #else
655: UINT16 ip = m_pc - SREG_BASE(CS);
656: UINT16 cs = SREG(CS);
657: #if defined(HAS_I286)
658: i80286_code_descriptor(selector, address, 2);
659: #else
660: SREG(CS) = selector;
661: i386_load_segment_descriptor(CS);
662: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
663: #endif
664: PUSH(cs);
665: PUSH(ip);
666: CHANGE_PC(m_pc);
667: #endif
668: }
669: */
670:
1.1.1.29 root 671: UINT16 i386_read_stack()
672: {
673: #if defined(HAS_I386)
674: UINT32 ea, new_esp;
675: if( STACK_32BIT ) {
676: new_esp = REG32(ESP) + 2;
677: ea = i386_translate(SS, new_esp - 2, 0);
678: } else {
679: new_esp = REG16(SP) + 2;
680: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
681: }
682: return READ16(ea);
683: #else
684: UINT16 sp = m_regs.w[SP] + 2;
685: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
686: #endif
687: }
688:
1.1 root 689: /* ----------------------------------------------------------------------------
690: main
691: ---------------------------------------------------------------------------- */
692:
1.1.1.28 root 693: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
694: {
695: if(dwCtrlType == CTRL_BREAK_EVENT) {
696: // try to finish this program normally
697: m_halted = true;
698: return TRUE;
699: } else if(dwCtrlType == CTRL_C_EVENT) {
700: ctrl_c_pressed = true;
701: return TRUE;
702: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
703: // this program will be terminated abnormally, do minimum end process
704: exit_handler();
705: exit(1);
706: }
707: return FALSE;
708: }
709:
710: void exit_handler()
711: {
712: if(temp_file_created) {
713: DeleteFile(temp_file_path);
714: temp_file_created = false;
715: }
716: if(key_buf_char != NULL) {
717: key_buf_char->release();
718: delete key_buf_char;
719: key_buf_char = NULL;
720: }
721: if(key_buf_scan != NULL) {
722: key_buf_scan->release();
723: delete key_buf_scan;
724: key_buf_scan = NULL;
725: }
1.1.1.32! root 726: #ifdef SUPPORT_XMS
! 727: msdos_xms_release();
! 728: #endif
1.1.1.28 root 729: hardware_release();
730: }
731:
732: #ifdef USE_THREAD
733: DWORD WINAPI vram_thread(LPVOID)
734: {
735: while(!m_halted) {
736: EnterCriticalSection(&vram_crit_sect);
737: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
738: vram_flush_char();
739: }
740: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
741: vram_flush_attr();
742: }
743: vram_last_length_char = vram_length_char;
744: vram_last_length_attr = vram_length_attr;
745: LeaveCriticalSection(&vram_crit_sect);
746: // this is about half the maximum keyboard repeat rate - any
747: // lower tends to be jerky, any higher misses updates
748: Sleep(15);
749: }
750: return 0;
751: }
752: #endif
753:
754: long get_section_in_exec_file(FILE *fp, char *name)
755: {
756: UINT8 header[0x400];
757:
758: long position = ftell(fp);
759: fseek(fp, 0, SEEK_SET);
760: fread(header, sizeof(header), 1, fp);
761: fseek(fp, position, SEEK_SET);
762:
763: try {
764: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
765: DWORD dwTopOfSignature = dosHeader->e_lfanew;
766: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
767: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
768: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
769: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
770:
771: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
772: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
773: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
774: return(sectionHeader->PointerToRawData);
775: }
776: }
777: } catch(...) {
778: }
779: return(0);
780: }
781:
1.1.1.10 root 782: bool is_started_from_command_prompt()
783: {
1.1.1.18 root 784: bool ret = false;
785:
786: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
787: if(hLibrary) {
788: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
789: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
790: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
791: if(lpfnGetConsoleProcessList) {
792: DWORD pl;
793: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
794: FreeLibrary(hLibrary);
795: return(ret);
796: }
797: FreeLibrary(hLibrary);
798: }
799:
800: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
801: if(hSnapshot != INVALID_HANDLE_VALUE) {
802: DWORD dwParentProcessID = 0;
803: PROCESSENTRY32 pe32;
804: pe32.dwSize = sizeof(PROCESSENTRY32);
805: if(Process32First(hSnapshot, &pe32)) {
806: do {
807: if(pe32.th32ProcessID == GetCurrentProcessId()) {
808: dwParentProcessID = pe32.th32ParentProcessID;
809: break;
810: }
811: } while(Process32Next(hSnapshot, &pe32));
812: }
813: CloseHandle(hSnapshot);
814: if(dwParentProcessID != 0) {
815: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
816: if(hProcess != NULL) {
817: HMODULE hMod;
818: DWORD cbNeeded;
819: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
820: char module_name[MAX_PATH];
821: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
822: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
823: }
824: }
825: CloseHandle(hProcess);
826: }
827: }
828: }
829: return(ret);
1.1.1.14 root 830: }
831:
832: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
833: {
1.1.1.24 root 834: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 835: OSVERSIONINFOEX osvi;
836: DWORDLONG dwlConditionMask = 0;
837: int op = VER_GREATER_EQUAL;
838:
839: // Initialize the OSVERSIONINFOEX structure.
840: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
841: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
842: osvi.dwMajorVersion = dwMajorVersion;
843: osvi.dwMinorVersion = dwMinorVersion;
844: osvi.wServicePackMajor = wServicePackMajor;
845: osvi.wServicePackMinor = wServicePackMinor;
846:
847: // Initialize the condition mask.
848: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
849: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
850: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
851: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
852:
853: // Perform the test.
854: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
855: }
856:
1.1.1.27 root 857: void get_sio_port_numbers()
858: {
859: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
860: HDEVINFO hDevInfo = 0;
861: HKEY hKey = 0;
862: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
863: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
864: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
865: char chData[256];
866: DWORD dwType = 0;
867: DWORD dwSize = sizeof(chData);
868: int port_number = 0;
869:
870: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
871: if(_strnicmp(chData, "COM", 3) == 0) {
872: port_number = atoi(chData + 3);
873: }
874: }
875: RegCloseKey(hKey);
876:
1.1.1.29 root 877: if(sio_port_number[0] == port_number || sio_port_number[1] == port_number || sio_port_number[2] == port_number || sio_port_number[3] == port_number) {
1.1.1.27 root 878: continue;
879: }
880: if(sio_port_number[0] == 0) {
881: sio_port_number[0] = port_number;
882: } else if(sio_port_number[1] == 0) {
883: sio_port_number[1] = port_number;
1.1.1.29 root 884: } else if(sio_port_number[2] == 0) {
885: sio_port_number[2] = port_number;
886: } else if(sio_port_number[3] == 0) {
887: sio_port_number[3] = port_number;
1.1.1.27 root 888: }
1.1.1.29 root 889: if(sio_port_number[0] != 0 && sio_port_number[1] != 0 && sio_port_number[2] != 0 && sio_port_number[3] != 0) {
1.1.1.27 root 890: break;
891: }
892: }
893: }
894: }
895: }
896:
1.1.1.28 root 897: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
898:
1.1 root 899: int main(int argc, char *argv[], char *envp[])
900: {
1.1.1.9 root 901: int arg_offset = 0;
902: int standard_env = 0;
1.1.1.14 root 903: int buf_width = 0, buf_height = 0;
1.1.1.28 root 904: bool get_console_info_success = false;
905: bool screen_size_changed = false;
906:
907: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
908: GetModuleFileName(NULL, path, MAX_PATH);
909: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 910:
1.1.1.27 root 911: char dummy_argv_0[] = "msdos.exe";
912: char dummy_argv_1[MAX_PATH];
913: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
914: char new_exec_file[MAX_PATH];
915: bool convert_cmd_file = false;
1.1.1.28 root 916: unsigned int code_page = 0;
1.1.1.27 root 917:
918: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 919: // check if command file is embedded to this execution file
920: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 921: FILE* fp = fopen(full, "rb");
1.1.1.28 root 922: long offset = get_section_in_exec_file(fp, ".msdos");
923: if(offset != 0) {
1.1.1.30 root 924: UINT8 buffer[16];
1.1.1.28 root 925: fseek(fp, offset, SEEK_SET);
926: fread(buffer, sizeof(buffer), 1, fp);
927:
928: // restore flags
929: stay_busy = ((buffer[0] & 0x01) != 0);
930: no_windows = ((buffer[0] & 0x02) != 0);
931: standard_env = ((buffer[0] & 0x04) != 0);
932: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
933: limit_max_memory = ((buffer[0] & 0x10) != 0);
934: if((buffer[0] & 0x20) != 0) {
935: get_sio_port_numbers();
936: }
937: if((buffer[0] & 0x40) != 0) {
938: UMB_TOP = EMS_TOP + EMS_SIZE;
939: support_ems = true;
1.1.1.30 root 940: }
1.1.1.27 root 941: #ifdef SUPPORT_XMS
1.1.1.30 root 942: if((buffer[0] & 0x80) != 0) {
1.1.1.28 root 943: support_xms = true;
944: }
1.1.1.30 root 945: #endif
1.1.1.28 root 946: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
947: buf_width = buffer[1] | (buffer[2] << 8);
948: buf_height = buffer[3] | (buffer[4] << 8);
949: }
950: if(buffer[5] != 0) {
1.1.1.30 root 951: dos_major_version = buffer[5];
952: dos_minor_version = buffer[6];
953: }
954: if(buffer[7] != 0) {
955: win_major_version = buffer[7];
956: win_minor_version = buffer[8];
1.1.1.28 root 957: }
1.1.1.30 root 958: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
1.1.1.28 root 959: SetConsoleCP(code_page);
960: SetConsoleOutputCP(code_page);
961: }
1.1.1.30 root 962: int name_len = buffer[11];
963: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
1.1.1.28 root 964:
965: // restore command file name
966: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
967: fread(dummy_argv_1, name_len, 1, fp);
968:
969: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
970: // if original command file exists, create a temporary file name
971: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
972: // create a temporary command file in the current director
973: DeleteFile(dummy_argv_1);
1.1.1.27 root 974: } else {
1.1.1.28 root 975: // create a temporary command file in the temporary folder
976: GetTempPath(MAX_PATH, path);
977: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
978: DeleteFile(dummy_argv_1);
979: } else {
980: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
981: }
1.1.1.27 root 982: }
1.1.1.28 root 983: // check the command file type
984: fread(buffer, 2, 1, fp);
985: fseek(fp, -2, SEEK_CUR);
986: if(memcmp(buffer, "MZ", 2) != 0) {
987: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
988: } else {
989: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 990: }
991: }
1.1.1.28 root 992:
993: // restore command file
994: FILE* fo = fopen(dummy_argv_1, "wb");
995: for(int i = 0; i < file_len; i++) {
996: fputc(fgetc(fp), fo);
997: }
998: fclose(fo);
999:
1000: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
1001: temp_file_created = true;
1002: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
1003:
1004: // adjust argc/argv
1005: for(int i = 1; i < argc && (i + 1) < 256; i++) {
1006: dummy_argv[i + 1] = argv[i];
1007: }
1008: argc++;
1009: argv = dummy_argv;
1.1.1.27 root 1010: }
1011: fclose(fp);
1012: }
1.1.1.9 root 1013: for(int i = 1; i < argc; i++) {
1.1.1.25 root 1014: if(_strnicmp(argv[i], "-b", 2) == 0) {
1015: stay_busy = true;
1016: arg_offset++;
1.1.1.27 root 1017: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
1018: if(argv[i][2] != '\0') {
1019: strcpy(new_exec_file, &argv[i][2]);
1020: } else {
1021: strcpy(new_exec_file, "new_exec_file.exe");
1022: }
1023: convert_cmd_file = true;
1024: arg_offset++;
1.1.1.28 root 1025: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
1026: if(IS_NUMERIC(argv[i][2])) {
1027: code_page = atoi(&argv[i][2]);
1028: } else {
1029: code_page = GetConsoleCP();
1030: }
1031: arg_offset++;
1.1.1.25 root 1032: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
1033: no_windows = true;
1034: arg_offset++;
1035: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 1036: standard_env = 1;
1037: arg_offset++;
1.1.1.14 root 1038: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
1039: ignore_illegal_insn = true;
1040: arg_offset++;
1041: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
1042: limit_max_memory = true;
1043: arg_offset++;
1044: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 1045: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
1046: buf_width = buf_height = 0;
1047: }
1048: if(buf_width <= 0 || buf_width > 0x7fff) {
1049: buf_width = 80;
1050: }
1051: if(buf_height <= 0 || buf_height > 0x7fff) {
1052: buf_height = 25;
1053: }
1.1.1.14 root 1054: arg_offset++;
1.1.1.25 root 1055: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 1056: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29 root 1057: char *p0 = &argv[i][2], *p1, *p2, *p3;
1058: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
1059: sio_port_number[1] = atoi(p1 + 1);
1060: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
1061: sio_port_number[2] = atoi(p2 + 1);
1062: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
1063: sio_port_number[3] = atoi(p3 + 1);
1064: }
1065: }
1.1.1.25 root 1066: }
1.1.1.29 root 1067: sio_port_number[0] = atoi(p0);
1.1.1.25 root 1068: }
1.1.1.29 root 1069: if(sio_port_number[0] == 0 || sio_port_number[1] == 0 || sio_port_number[2] == 0 || sio_port_number[3] == 0) {
1.1.1.27 root 1070: get_sio_port_numbers();
1.1.1.25 root 1071: }
1072: arg_offset++;
1.1.1.9 root 1073: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 1074: 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.30 root 1075: dos_major_version = argv[i][2] - '0';
1076: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1077: }
1078: arg_offset++;
1079: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
1080: 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]))) {
1081: win_major_version = argv[i][2] - '0';
1082: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 1083: }
1084: arg_offset++;
1.1.1.25 root 1085: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
1086: UMB_TOP = EMS_TOP + EMS_SIZE;
1087: support_ems = true;
1088: #ifdef SUPPORT_XMS
1089: support_xms = true;
1090: #endif
1091: arg_offset++;
1.1.1.9 root 1092: } else {
1093: break;
1094: }
1095: }
1096: if(argc < 2 + arg_offset) {
1.1 root 1097: #ifdef _WIN64
1.1.1.14 root 1098: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 1099: #else
1.1.1.14 root 1100: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 1101: #endif
1.1.1.25 root 1102: fprintf(stderr,
1.1.1.28 root 1103: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.30 root 1104: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
1.1.1.25 root 1105: "\n"
1106: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 1107: #ifdef _WIN64
1.1.1.27 root 1108: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 1109: #else
1.1.1.27 root 1110: "\t-c\tconvert command file to 32bit execution file\n"
1111: #endif
1.1.1.28 root 1112: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 1113: "\t-d\tpretend running under straight DOS, not Windows\n"
1114: "\t-e\tuse a reduced environment block\n"
1115: "\t-i\tignore invalid instructions\n"
1116: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
1117: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
1118: "\t-s\tenable serial I/O and set host's COM port numbers\n"
1119: "\t-v\tset the DOS version\n"
1.1.1.30 root 1120: "\t-w\tset the Windows version\n"
1.1.1.19 root 1121: #ifdef SUPPORT_XMS
1.1.1.28 root 1122: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 1123: #else
1.1.1.28 root 1124: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 1125: #endif
1126: );
1.1.1.10 root 1127:
1128: if(!is_started_from_command_prompt()) {
1129: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
1130: while(!_kbhit()) {
1131: Sleep(10);
1132: }
1133: }
1.1.1.20 root 1134: #ifdef _DEBUG
1135: _CrtDumpMemoryLeaks();
1136: #endif
1.1 root 1137: return(EXIT_FAILURE);
1138: }
1.1.1.27 root 1139: if(convert_cmd_file) {
1140: retval = EXIT_FAILURE;
1.1.1.28 root 1141: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 1142: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 1143: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 1144:
1.1.1.28 root 1145: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
1146: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
1147: } else if((fp = fopen(full, "rb")) == NULL) {
1148: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 1149: } else {
1.1.1.28 root 1150: long offset = get_section_in_exec_file(fp, ".msdos");
1151: if(offset != 0) {
1152: UINT8 buffer[14];
1153: fseek(fp, offset, SEEK_SET);
1154: fread(buffer, sizeof(buffer), 1, fp);
1155: memset(path, 0, sizeof(path));
1156: fread(path, buffer[9], 1, fp);
1157: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
1158: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
1159: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
1160: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
1161: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
1162: } else {
1163: // read pe header of msdos.exe
1164: UINT8 header[0x400];
1165: fseek(fp, 0, SEEK_SET);
1166: fread(header, sizeof(header), 1, fp);
1167:
1168: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
1169: DWORD dwTopOfSignature = dosHeader->e_lfanew;
1170: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
1171: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
1172: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
1173: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
1174: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
1175:
1176: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
1177: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
1178: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
1179: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
1180: if(dwExtraLastSectionBytes != 0) {
1181: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
1182: dwLastSectionSize += dwRemain;
1183: }
1184: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
1185:
1186: // store msdos.exe
1187: fseek(fp, 0, SEEK_SET);
1188: for(int i = 0; i < dwEndOfFile; i++) {
1189: if((data = fgetc(fp)) != EOF) {
1190: fputc(data, fo);
1191: } else {
1192: // we should not reach here :-(
1193: fputc(0, fo);
1194: }
1195: }
1196:
1197: // store options
1198: UINT8 flags = 0;
1199: if(stay_busy) {
1200: flags |= 0x01;
1201: }
1202: if(no_windows) {
1203: flags |= 0x02;
1204: }
1205: if(standard_env) {
1206: flags |= 0x04;
1207: }
1208: if(ignore_illegal_insn) {
1209: flags |= 0x08;
1210: }
1211: if(limit_max_memory) {
1212: flags |= 0x10;
1213: }
1.1.1.29 root 1214: if(sio_port_number[0] != 0 || sio_port_number[1] != 0 || sio_port_number[2] != 0 || sio_port_number[3] != 0) {
1.1.1.28 root 1215: flags |= 0x20;
1216: }
1217: if(support_ems) {
1218: flags |= 0x40;
1219: }
1.1.1.30 root 1220: #ifdef SUPPORT_XMS
1221: if(support_xms) {
1222: flags |= 0x80;
1223: }
1224: #endif
1.1.1.28 root 1225:
1226: fputc(flags, fo);
1227: fputc((buf_width >> 0) & 0xff, fo);
1228: fputc((buf_width >> 8) & 0xff, fo);
1229: fputc((buf_height >> 0) & 0xff, fo);
1230: fputc((buf_height >> 8) & 0xff, fo);
1.1.1.30 root 1231: fputc(dos_major_version, fo);
1232: fputc(dos_minor_version, fo);
1233: fputc(win_major_version, fo);
1234: fputc(win_minor_version, fo);
1.1.1.28 root 1235: fputc((code_page >> 0) & 0xff, fo);
1236: fputc((code_page >> 8) & 0xff, fo);
1237:
1238: // store command file info
1239: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
1240: int name_len = strlen(name);
1241: fseek(fs, 0, SEEK_END);
1242: long file_size = ftell(fs);
1243:
1244: fputc(name_len, fo);
1245: fputc((file_size >> 0) & 0xff, fo);
1246: fputc((file_size >> 8) & 0xff, fo);
1247: fputc((file_size >> 16) & 0xff, fo);
1248: fputc((file_size >> 24) & 0xff, fo);
1249: fwrite(name, name_len, 1, fo);
1250:
1251: // store command file
1252: fseek(fs, 0, SEEK_SET);
1253: for(int i = 0; i < file_size; i++) {
1254: if((data = fgetc(fs)) != EOF) {
1255: fputc(data, fo);
1256: } else {
1257: // we should not reach here :-(
1258: fputc(0, fo);
1259: }
1260: }
1261:
1262: // store padding data and update pe header
1.1.1.29 root 1263: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
1264: coffHeader->NumberOfSections++;
1265: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
1266: memcpy(newSectionHeader->Name, ".msdos", 6);
1267: newSectionHeader->VirtualAddress = dwVirtualAddress;
1268: newSectionHeader->PointerToRawData = dwEndOfFile;
1269: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 1270: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
1271: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
1272: if(dwExtraRawBytes != 0) {
1.1.1.29 root 1273: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 1274: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
1275: for(int i = 0; i < dwRemain; i++) {
1.1.1.29 root 1276: if(i < 2) {
1277: fputc(padding[i & 15], fo);
1278: } else {
1279: fputc(padding[(i - 2) & 15], fo);
1280: }
1.1.1.28 root 1281: }
1282: newSectionHeader->SizeOfRawData += dwRemain;
1283: }
1284: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
1285:
1286: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
1287: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
1288: if(dwExtraNewSectionBytes != 0) {
1289: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
1290: dwNewSectionSize += dwRemain;
1291: }
1292: optionalHeader->SizeOfImage += dwNewSectionSize;
1293:
1294: fseek(fo, 0, SEEK_SET);
1295: fwrite(header, sizeof(header), 1, fo);
1296:
1297: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
1298: retval = EXIT_SUCCESS;
1.1.1.27 root 1299: }
1300: }
1301: if(fp != NULL) {
1302: fclose(fp);
1303: }
1304: if(fs != NULL) {
1305: fclose(fs);
1306: }
1307: if(fo != NULL) {
1308: fclose(fo);
1309: }
1310: }
1311: #ifdef _DEBUG
1312: _CrtDumpMemoryLeaks();
1313: #endif
1314: return(retval);
1315: }
1.1 root 1316:
1.1.1.14 root 1317: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
1318:
1.1.1.23 root 1319: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 1320: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 1321: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 1322:
1.1.1.28 root 1323: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 1324: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 1325: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 1326:
1.1.1.14 root 1327: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
1328: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
1329: SCR_BUF(y,x).Char.AsciiChar = ' ';
1330: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 1331: }
1332: }
1.1.1.28 root 1333: if(get_console_info_success) {
1.1.1.12 root 1334: scr_width = csbi.dwSize.X;
1.1.1.14 root 1335: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1336:
1.1.1.28 root 1337: // v-text shadow buffer size must be lesser than 0x7fd0
1338: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 1339: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
1340: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
1341: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 1342: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 1343: scr_width = 80;
1344: scr_height = 25;
1345: }
1.1.1.28 root 1346: screen_size_changed = true;
1.1.1.14 root 1347: }
1.1.1.12 root 1348: } else {
1349: // for a proof (not a console)
1350: scr_width = 80;
1351: scr_height = 25;
1352: }
1.1.1.14 root 1353: scr_buf_size.X = scr_width;
1354: scr_buf_size.Y = scr_height;
1355: scr_buf_pos.X = scr_buf_pos.Y = 0;
1356: scr_top = csbi.srWindow.Top;
1.1 root 1357: cursor_moved = false;
1358:
1.1.1.25 root 1359: key_buf_char = new FIFO(256);
1360: key_buf_scan = new FIFO(256);
1.1 root 1361:
1362: hardware_init();
1363:
1.1.1.9 root 1364: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 1365: retval = EXIT_FAILURE;
1366: } else {
1.1.1.27 root 1367: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 1368: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
1369: #endif
1370: SetConsoleCtrlHandler(ctrl_handler, TRUE);
1371:
1.1.1.28 root 1372: if(screen_size_changed) {
1.1.1.24 root 1373: change_console_size(scr_width, scr_height);
1374: }
1.1.1.8 root 1375: TIMECAPS caps;
1376: timeGetDevCaps(&caps, sizeof(TIMECAPS));
1377: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 1378: #ifdef USE_THREAD
1379: InitializeCriticalSection(&vram_crit_sect);
1380: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
1381: #endif
1.1 root 1382: hardware_run();
1.1.1.14 root 1383: #ifdef USE_THREAD
1384: vram_flush();
1385: DeleteCriticalSection(&vram_crit_sect);
1386: #endif
1.1.1.24 root 1387: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 1388:
1.1.1.24 root 1389: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 1390: if(get_console_info_success) {
1.1.1.23 root 1391: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 1392: if(restore_console_on_exit) {
1.1.1.14 root 1393: // window can't be bigger than buffer,
1394: // buffer can't be smaller than window,
1395: // so make a tiny window,
1396: // set the required buffer,
1397: // then set the required window
1398: SMALL_RECT rect;
1399: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1400: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 1401: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 1402: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 1403: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1404: }
1.1.1.14 root 1405: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1406: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 1407: }
1.1.1.24 root 1408: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
1409:
1.1 root 1410: msdos_finish();
1.1.1.14 root 1411:
1412: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 1413: }
1414:
1.1.1.10 root 1415: hardware_finish();
1416:
1.1.1.28 root 1417: if(key_buf_char != NULL) {
1418: key_buf_char->release();
1419: delete key_buf_char;
1420: key_buf_char = NULL;
1421: }
1422: if(key_buf_scan != NULL) {
1423: key_buf_scan->release();
1424: delete key_buf_scan;
1425: key_buf_scan = NULL;
1426: }
1427: if(temp_file_created) {
1428: DeleteFile(temp_file_path);
1429: temp_file_created = false;
1430: }
1431: // if(argv == dummy_argv) {
1432: // if(!is_started_from_command_prompt()) {
1433: // fprintf(stderr, "\nHit any key to quit...");
1434: // while(!_kbhit()) {
1435: // Sleep(10);
1436: // }
1437: // }
1438: // }
1.1.1.20 root 1439: #ifdef _DEBUG
1440: _CrtDumpMemoryLeaks();
1441: #endif
1.1 root 1442: return(retval);
1443: }
1444:
1.1.1.20 root 1445: /* ----------------------------------------------------------------------------
1446: console
1447: ---------------------------------------------------------------------------- */
1448:
1.1.1.14 root 1449: void change_console_size(int width, int height)
1.1.1.12 root 1450: {
1.1.1.23 root 1451: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 1452: CONSOLE_SCREEN_BUFFER_INFO csbi;
1453: SMALL_RECT rect;
1454: COORD co;
1455:
1456: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 1457: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
1458: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
1459: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
1460: SET_RECT(rect, 0, 0, width - 1, height - 1);
1461: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1462: } else if(csbi.dwCursorPosition.Y > height - 1) {
1463: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
1464: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1465: SET_RECT(rect, 0, 0, width - 1, height - 1);
1466: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 1467: }
1468: }
1.1.1.14 root 1469: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 1470: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 1471: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 1472: SetConsoleCursorPosition(hStdout, co);
1473: cursor_moved = true;
1474: }
1.1.1.14 root 1475:
1476: // window can't be bigger than buffer,
1477: // buffer can't be smaller than window,
1478: // so make a tiny window,
1479: // set the required buffer,
1480: // then set the required window
1481: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 1482: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 1483: co.X = width;
1484: co.Y = height;
1.1.1.12 root 1485: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 1486: SET_RECT(rect, 0, 0, width - 1, height - 1);
1487: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1488:
1489: scr_width = scr_buf_size.X = width;
1490: scr_height = scr_buf_size.Y = height;
1491: scr_top = 0;
1492:
1493: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1494:
1495: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 1496: text_vram_end_address = text_vram_top_address + regen;
1497: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1498:
1.1.1.14 root 1499: if(regen > 0x4000) {
1500: regen = 0x8000;
1501: vram_pages = 1;
1502: } else if(regen > 0x2000) {
1503: regen = 0x4000;
1504: vram_pages = 2;
1505: } else if(regen > 0x1000) {
1506: regen = 0x2000;
1507: vram_pages = 4;
1508: } else {
1509: regen = 0x1000;
1510: vram_pages = 8;
1511: }
1.1.1.15 root 1512: *(UINT16 *)(mem + 0x44a) = scr_width;
1513: *(UINT16 *)(mem + 0x44c) = regen;
1514: *(UINT8 *)(mem + 0x484) = scr_height - 1;
1515:
1.1.1.24 root 1516: mouse.min_position.x = 0;
1517: mouse.min_position.y = 0;
1518: mouse.max_position.x = 8 * scr_width - 1;
1519: mouse.max_position.y = 8 * scr_height - 1;
1520:
1.1.1.15 root 1521: restore_console_on_exit = true;
1.1.1.14 root 1522: }
1523:
1524: void clear_scr_buffer(WORD attr)
1525: {
1526: for(int y = 0; y < scr_height; y++) {
1527: for(int x = 0; x < scr_width; x++) {
1528: SCR_BUF(y,x).Char.AsciiChar = ' ';
1529: SCR_BUF(y,x).Attributes = attr;
1530: }
1531: }
1.1.1.12 root 1532: }
1533:
1.1.1.24 root 1534: bool update_console_input()
1.1 root 1535: {
1.1.1.23 root 1536: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 1537: DWORD dwNumberOfEvents = 0;
1.1 root 1538: DWORD dwRead;
1539: INPUT_RECORD ir[16];
1.1.1.24 root 1540: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
1541: bool result = false;
1.1 root 1542:
1.1.1.8 root 1543: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
1544: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
1545: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 1546: if(ir[i].EventType & MOUSE_EVENT) {
1547: if(mouse.active) {
1548: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
1549: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
1550: static const DWORD bits[] = {
1551: FROM_LEFT_1ST_BUTTON_PRESSED, // left
1552: RIGHTMOST_BUTTON_PRESSED, // right
1553: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
1.1.1.14 root 1554: };
1.1.1.24 root 1555: bool prev_status = mouse.buttons[i].status;
1556: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
1557:
1558: if(!prev_status && mouse.buttons[i].status) {
1559: mouse.buttons[i].pressed_times++;
1560: mouse.buttons[i].pressed_position.x = mouse.position.x;
1561: mouse.buttons[i].pressed_position.y = mouse.position.y;
1562: mouse.status |= 2 << (i * 2);
1563: } else if(prev_status && !mouse.buttons[i].status) {
1564: mouse.buttons[i].released_times++;
1565: mouse.buttons[i].released_position.x = mouse.position.x;
1566: mouse.buttons[i].released_position.y = mouse.position.y;
1567: mouse.status |= 4 << (i * 2);
1568: }
1.1.1.14 root 1569: }
1.1.1.24 root 1570: } else if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) {
1571: // NOTE: if restore_console_on_exit, console is not scrolled
1572: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
1573: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.14 root 1574: }
1.1.1.28 root 1575: // FIXME: character size is always 8x8 ???
1576: int x = 3 + 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
1577: int y = 4 + 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
1.1.1.24 root 1578: if(mouse.position.x != x || mouse.position.y != y) {
1579: mouse.position.x = x;
1580: mouse.position.y = y;
1581: mouse.status |= 1;
1.1.1.14 root 1582: }
1583: }
1584: }
1.1.1.24 root 1585: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.28 root 1586: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 1587: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.14 root 1588: if(!ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 1589: // break
1.1.1.14 root 1590: kbd_data |= 0x80;
1.1.1.24 root 1591: } else {
1.1.1.28 root 1592: // make
1.1.1.24 root 1593: kbd_data &= 0x7f;
1594:
1595: // update dos key buffer
1596: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
1597: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
1598:
1599: if(chr == 0) {
1600: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1601: if(scn >= 0x3b && scn <= 0x44) {
1602: scn += 0x68 - 0x3b; // F1 to F10
1603: } else if(scn == 0x57 || scn == 0x58) {
1604: scn += 0x8b - 0x57; // F11 & F12
1605: } else if(scn >= 0x47 && scn <= 0x53) {
1606: scn += 0x97 - 0x47; // edit/arrow clusters
1607: } else if(scn == 0x35) {
1608: scn = 0xa4; // keypad /
1609: }
1610: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1611: if(scn == 0x07) {
1612: chr = 0x1e; // Ctrl+^
1613: } else if(scn == 0x0c) {
1614: chr = 0x1f; // Ctrl+_
1615: } else if(scn >= 0x35 && scn <= 0x58) {
1616: static const UINT8 ctrl_map[] = {
1617: 0x95, // keypad /
1618: 0,
1619: 0x96, // keypad *
1620: 0, 0, 0,
1621: 0x5e, // F1
1622: 0x5f, // F2
1623: 0x60, // F3
1624: 0x61, // F4
1625: 0x62, // F5
1626: 0x63, // F6
1627: 0x64, // F7
1628: 0x65, // F8
1629: 0x66, // F9
1630: 0x67, // F10
1631: 0,
1632: 0,
1633: 0x77, // Home
1634: 0x8d, // Up
1635: 0x84, // PgUp
1636: 0x8e, // keypad -
1637: 0x73, // Left
1638: 0x8f, // keypad center
1639: 0x74, // Right
1640: 0x90, // keyapd +
1641: 0x75, // End
1642: 0x91, // Down
1643: 0x76, // PgDn
1644: 0x92, // Insert
1645: 0x93, // Delete
1646: 0, 0, 0,
1647: 0x89, // F11
1648: 0x8a, // F12
1649: };
1650: scn = ctrl_map[scn - 0x35];
1651: }
1652: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1653: if(scn >= 0x3b && scn <= 0x44) {
1654: scn += 0x54 - 0x3b; // F1 to F10
1655: } else if(scn == 0x57 || scn == 0x58) {
1656: scn += 0x87 - 0x57; // F11 & F12
1657: }
1658: } else if(scn == 0x57 || scn == 0x58) {
1659: scn += 0x85 - 0x57;
1660: }
1661: // ignore shift, ctrl, alt, win and menu keys
1662: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1.1.1.32! root 1663: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 1664: if(chr == 0) {
! 1665: key_buf_char->write(0x00);
! 1666: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
! 1667: }
! 1668: key_buf_char->write(chr);
! 1669: key_buf_scan->write(scn);
1.1.1.24 root 1670: }
1671: }
1672: } else {
1673: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1674: chr = 0;
1675: if(scn >= 0x02 && scn <= 0x0e) {
1676: scn += 0x78 - 0x02; // 1 to 0 - =
1677: }
1678: }
1.1.1.32! root 1679: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 1680: key_buf_char->write(chr);
! 1681: key_buf_scan->write(scn);
! 1682: }
1.1.1.24 root 1683: }
1.1 root 1684: }
1.1.1.24 root 1685: result = key_changed = true;
1.1 root 1686: }
1687: }
1688: }
1689: }
1.1.1.24 root 1690: return(result);
1.1.1.8 root 1691: }
1692:
1.1.1.14 root 1693: bool update_key_buffer()
1.1.1.8 root 1694: {
1.1.1.32! root 1695: return(update_console_input() || (key_buf_char != NULL && key_buf_char->count() != 0));
1.1.1.8 root 1696: }
1697:
1.1.1.20 root 1698: /* ----------------------------------------------------------------------------
1699: MS-DOS virtual machine
1700: ---------------------------------------------------------------------------- */
1701:
1.1.1.32! root 1702: static const struct {
! 1703: UINT16 code;
! 1704: char *message_english;
! 1705: char *message_japanese;
! 1706: } standard_error_table[] = {
! 1707: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
! 1708: {0x02, "File not found", "�t�@�C����������܂���."},
! 1709: {0x03, "Path not found", "�p�X��������܂���."},
! 1710: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
! 1711: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
! 1712: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
! 1713: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
! 1714: {0x08, "Insufficient memory", "������������܂���."},
! 1715: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
! 1716: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
! 1717: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
! 1718: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
! 1719: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
! 1720: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
! 1721: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
! 1722: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
! 1723: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
! 1724: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
! 1725: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
! 1726: {0x15, "Not ready", "�������ł��Ă��܂���."},
! 1727: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
! 1728: {0x17, "Data error", "�f�[�^�G���[�ł�."},
! 1729: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
! 1730: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
! 1731: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
! 1732: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
! 1733: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
! 1734: {0x1D, "Write fault error", "�������݃G���[�ł�."},
! 1735: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
! 1736: {0x1F, "General failure", "�G���[�ł�."},
! 1737: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
! 1738: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
! 1739: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
! 1740: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
! 1741: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
! 1742: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
! 1743: {0x26, "Out of input", "���͂��I���܂���."},
! 1744: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
! 1745: /*
! 1746: {0x32, "Network request not supported", NULL},
! 1747: {0x33, "Remote computer not listening", NULL},
! 1748: {0x34, "Duplicate name on network", NULL},
! 1749: {0x35, "Network name not found", NULL},
! 1750: {0x36, "Network busy", NULL},
! 1751: {0x37, "Network device no longer exists", NULL},
! 1752: {0x38, "Network BIOS command limit exceeded", NULL},
! 1753: {0x39, "Network adapter hardware error", NULL},
! 1754: {0x3A, "Incorrect response from network", NULL},
! 1755: {0x3B, "Unexpected network error", NULL},
! 1756: {0x3C, "Incompatible remote adapter", NULL},
! 1757: {0x3D, "Print queue full", NULL},
! 1758: {0x3E, "Queue not full", NULL},
! 1759: {0x3F, "Not enough space to print file", NULL},
! 1760: {0x40, "Network name was deleted", NULL},
! 1761: {0x41, "Network: Access denied", NULL},
! 1762: {0x42, "Network device type incorrect", NULL},
! 1763: {0x43, "Network name not found", NULL},
! 1764: {0x44, "Network name limit exceeded", NULL},
! 1765: {0x45, "Network BIOS session limit exceeded", NULL},
! 1766: {0x46, "Temporarily paused", NULL},
! 1767: {0x47, "Network request not accepted", NULL},
! 1768: {0x48, "Network print/disk redirection paused", NULL},
! 1769: {0x49, "Network software not installed", NULL},
! 1770: {0x4A, "Unexpected adapter close", NULL},
! 1771: */
! 1772: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
! 1773: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�������܂���."},
! 1774: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
! 1775: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
! 1776: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
! 1777: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
! 1778: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
! 1779: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
! 1780: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
! 1781: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
! 1782: /*
! 1783: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
! 1784: {0x65, "Not ready", "�������ł��Ă��܂���."},
! 1785: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
! 1786: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
! 1787: {0x68, "Door open", "���o�[���܂��Ă��܂���."
! 1788: */
! 1789: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
! 1790: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
! 1791: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
! 1792: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
! 1793: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
! 1794: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
! 1795: };
! 1796:
! 1797: static const struct {
! 1798: UINT16 code;
! 1799: char *message_english;
! 1800: char *message_japanese;
! 1801: } param_error_table[] = {
! 1802: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
! 1803: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
! 1804: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
! 1805: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
! 1806: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
! 1807: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
! 1808: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
! 1809: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
! 1810: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
! 1811: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
! 1812: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
! 1813: };
! 1814:
! 1815: static const struct {
! 1816: UINT16 code;
! 1817: char *message_english;
! 1818: char *message_japanese;
! 1819: } critical_error_table[] = {
! 1820: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
! 1821: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
! 1822: {0x02, "Not ready", "�������ł��Ă��܂���."},
! 1823: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
! 1824: {0x04, "Data error", "�f�[�^�G���[�ł�."},
! 1825: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
! 1826: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
! 1827: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
! 1828: {0x08, "Sector not found", "�Z�N�^��������܂���."},
! 1829: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
! 1830: {0x0A, "Write fault error", "�������݃G���[�ł�."},
! 1831: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
! 1832: {0x0C, "General failure", "�G���[�ł�."},
! 1833: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
! 1834: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
! 1835: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
! 1836: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
! 1837: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
! 1838: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
! 1839: {0x13, "Out of input", "���͂��I���܂���."},
! 1840: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
! 1841: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
! 1842: };
! 1843:
1.1.1.20 root 1844: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1845: int msdos_psp_get_file_table(int fd, int psp_seg);
1846: void msdos_putch(UINT8 data);
1847:
1.1 root 1848: // process info
1849:
1850: process_t *msdos_process_info_create(UINT16 psp_seg)
1851: {
1852: for(int i = 0; i < MAX_PROCESS; i++) {
1853: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1854: memset(&process[i], 0, sizeof(process_t));
1855: process[i].psp = psp_seg;
1856: return(&process[i]);
1857: }
1858: }
1859: fatalerror("too many processes\n");
1860: return(NULL);
1861: }
1862:
1863: process_t *msdos_process_info_get(UINT16 psp_seg)
1864: {
1865: for(int i = 0; i < MAX_PROCESS; i++) {
1866: if(process[i].psp == psp_seg) {
1867: return(&process[i]);
1868: }
1869: }
1870: fatalerror("invalid psp address\n");
1871: return(NULL);
1872: }
1873:
1.1.1.23 root 1874: void msdos_sda_update(int psp_seg)
1875: {
1876: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1877:
1878: for(int i = 0; i < MAX_PROCESS; i++) {
1879: if(process[i].psp == psp_seg) {
1880: sda->switchar = process[i].switchar;
1881: sda->current_dta.w.l = process[i].dta.w.l;
1882: sda->current_dta.w.h = process[i].dta.w.h;
1883: sda->current_psp = process[i].psp;
1884: break;
1885: }
1886: }
1887: sda->malloc_strategy = malloc_strategy;
1888: sda->return_code = retval;
1889: sda->current_drive = _getdrive();
1890: }
1891:
1.1.1.13 root 1892: // dta info
1893:
1894: void msdos_dta_info_init()
1895: {
1.1.1.14 root 1896: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1897: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1898: }
1899: }
1900:
1901: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1902: {
1903: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1904: for(int i = 0; i < MAX_DTAINFO; i++) {
1905: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1906: if(free_dta == NULL) {
1.1.1.13 root 1907: free_dta = &dtalist[i];
1908: }
1.1.1.14 root 1909: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1910: return(&dtalist[i]);
1911: }
1912: }
1.1.1.14 root 1913: if(free_dta) {
1.1.1.13 root 1914: free_dta->psp = psp_seg;
1915: free_dta->dta = dta_laddr;
1916: return(free_dta);
1917: }
1918: fatalerror("too many dta\n");
1919: return(NULL);
1920: }
1921:
1922: void msdos_dta_info_free(UINT16 psp_seg)
1923: {
1.1.1.14 root 1924: for(int i = 0; i < MAX_DTAINFO; i++) {
1925: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1926: FindClose(dtalist[i].find_handle);
1927: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1928: }
1929: }
1930: }
1931:
1.1 root 1932: void msdos_cds_update(int drv)
1933: {
1934: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1935:
1936: memset(mem + CDS_TOP, 0, CDS_SIZE);
1937: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1938: cds->drive_attrib = 0x4000; // physical drive
1939: cds->physical_drive_number = drv;
1940: }
1941:
1.1.1.17 root 1942: // nls information tables
1943:
1944: // uppercase table (func 6502h)
1945: void msdos_upper_table_update()
1946: {
1947: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1948: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1949: UINT8 c[4];
1950: *(UINT32 *)c = 0; // reset internal conversion state
1951: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1952: c[0] = 0x80 + i;
1953: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1954: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1955: }
1956: }
1957:
1.1.1.23 root 1958: // lowercase table (func 6503h)
1959: void msdos_lower_table_update()
1960: {
1961: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
1962: for(unsigned i = 0; i < 0x80; ++i) {
1963: UINT8 c[4];
1964: *(UINT32 *)c = 0; // reset internal conversion state
1965: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1966: c[0] = 0x80 + i;
1967: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
1968: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1969: }
1970: }
1971:
1.1.1.17 root 1972: // filename uppercase table (func 6504h)
1973: void msdos_filename_upper_table_init()
1974: {
1975: // depended on (file)system, not on active codepage
1976: // temporary solution: just filling data
1977: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1978: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1979: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1980: }
1981: }
1982:
1983: // filaname terminator table (func 6505h)
1984: void msdos_filename_terminator_table_init()
1985: {
1986: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1987: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1988:
1989: data[2] = 1; // marker? (permissible character value)
1990: data[3] = 0x00; // 00h...FFh
1991: data[4] = 0xff;
1992: data[5] = 0; // marker? (excluded character)
1993: data[6] = 0x00; // 00h...20h
1994: data[7] = 0x20;
1995: data[8] = 2; // marker? (illegal characters for filename)
1996: data[9] = (UINT8)strlen(illegal_chars);
1997: memcpy(data + 10, illegal_chars, data[9]);
1998:
1999: // total length
2000: *(UINT16 *)data = (10 - 2) + data[9];
2001: }
2002:
2003: // collating table (func 6506h)
2004: void msdos_collating_table_update()
2005: {
2006: // temporary solution: just filling data
2007: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 2008: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 2009: mem[COLLATING_TABLE_TOP + 2 + i] = i;
2010: }
2011: }
2012:
1.1 root 2013: // dbcs
2014:
2015: void msdos_dbcs_table_update()
2016: {
2017: UINT8 dbcs_data[DBCS_SIZE];
2018: memset(dbcs_data, 0, sizeof(dbcs_data));
2019:
2020: CPINFO info;
2021: GetCPInfo(active_code_page, &info);
2022:
2023: if(info.MaxCharSize != 1) {
2024: for(int i = 0;; i += 2) {
2025: UINT8 lo = info.LeadByte[i + 0];
2026: UINT8 hi = info.LeadByte[i + 1];
2027: dbcs_data[2 + i + 0] = lo;
2028: dbcs_data[2 + i + 1] = hi;
2029: if(lo == 0 && hi == 0) {
2030: dbcs_data[0] = i + 2;
2031: break;
2032: }
2033: }
2034: } else {
2035: dbcs_data[0] = 2; // ???
2036: }
2037: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
2038: }
2039:
1.1.1.17 root 2040: void msdos_dbcs_table_finish()
2041: {
1.1.1.32! root 2042: if(system_code_page != _getmbcp()) {
1.1.1.17 root 2043: _setmbcp(system_code_page);
2044: }
1.1.1.32! root 2045: if(console_code_page != GetConsoleCP()) {
! 2046: SetConsoleCP(console_code_page);
! 2047: SetConsoleOutputCP(console_code_page);
! 2048: }
1.1.1.17 root 2049: }
2050:
2051: void msdos_nls_tables_init()
1.1 root 2052: {
1.1.1.32! root 2053: active_code_page = console_code_page = GetConsoleCP();
! 2054: system_code_page = _getmbcp();
! 2055:
! 2056: if(active_code_page != system_code_page) {
! 2057: if(_setmbcp(active_code_page) != 0) {
! 2058: active_code_page = system_code_page;
! 2059: }
! 2060: }
! 2061:
1.1.1.17 root 2062: msdos_upper_table_update();
1.1.1.23 root 2063: msdos_lower_table_update();
1.1.1.17 root 2064: msdos_filename_terminator_table_init();
2065: msdos_filename_upper_table_init();
2066: msdos_collating_table_update();
1.1 root 2067: msdos_dbcs_table_update();
2068: }
2069:
1.1.1.17 root 2070: void msdos_nls_tables_update()
1.1 root 2071: {
1.1.1.17 root 2072: msdos_dbcs_table_update();
2073: msdos_upper_table_update();
1.1.1.23 root 2074: msdos_lower_table_update();
2075: // msdos_collating_table_update();
1.1 root 2076: }
2077:
2078: int msdos_lead_byte_check(UINT8 code)
2079: {
2080: UINT8 *dbcs_table = mem + DBCS_TABLE;
2081:
2082: for(int i = 0;; i += 2) {
2083: UINT8 lo = dbcs_table[i + 0];
2084: UINT8 hi = dbcs_table[i + 1];
2085: if(lo == 0 && hi == 0) {
2086: break;
2087: }
2088: if(lo <= code && code <= hi) {
2089: return(1);
2090: }
2091: }
2092: return(0);
2093: }
2094:
1.1.1.20 root 2095: int msdos_ctrl_code_check(UINT8 code)
2096: {
1.1.1.22 root 2097: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 2098: }
2099:
1.1 root 2100: // file control
2101:
1.1.1.14 root 2102: char *msdos_remove_double_quote(char *path)
2103: {
2104: static char tmp[MAX_PATH];
2105:
2106: memset(tmp, 0, sizeof(tmp));
2107: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
2108: memcpy(tmp, path + 1, strlen(path) - 2);
2109: } else {
2110: strcpy(tmp, path);
2111: }
2112: return(tmp);
2113: }
2114:
1.1.1.32! root 2115: char *msdos_remove_end_separator(char *path)
! 2116: {
! 2117: static char tmp[MAX_PATH];
! 2118:
! 2119: strcpy(tmp, path);
! 2120: int len = strlen(tmp);
! 2121: if(len > 3 && tmp[len - 1] == '\\') {
! 2122: tmp[len - 1] = '\0';
! 2123: }
! 2124: return(tmp);
! 2125: }
! 2126:
1.1.1.14 root 2127: char *msdos_combine_path(char *dir, const char *file)
2128: {
2129: static char tmp[MAX_PATH];
2130: char *tmp_dir = msdos_remove_double_quote(dir);
2131:
2132: if(strlen(tmp_dir) == 0) {
2133: strcpy(tmp, file);
2134: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
2135: sprintf(tmp, "%s%s", tmp_dir, file);
2136: } else {
2137: sprintf(tmp, "%s\\%s", tmp_dir, file);
2138: }
2139: return(tmp);
2140: }
2141:
1.1 root 2142: char *msdos_trimmed_path(char *path, int lfn)
2143: {
2144: static char tmp[MAX_PATH];
2145:
2146: if(lfn) {
2147: strcpy(tmp, path);
2148: } else {
2149: // remove space in the path
2150: char *src = path, *dst = tmp;
2151:
2152: while(*src != '\0') {
2153: if(msdos_lead_byte_check(*src)) {
2154: *dst++ = *src++;
2155: *dst++ = *src++;
2156: } else if(*src != ' ') {
2157: *dst++ = *src++;
2158: } else {
2159: src++; // skip space
2160: }
2161: }
2162: *dst = '\0';
2163: }
1.1.1.14 root 2164: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
2165: // redirect C:\COMMAND.COM to comspec_path
2166: strcpy(tmp, comspec_path);
2167: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
2168: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
2169: static int root_drive_protected = -1;
2170: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
2171: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
2172:
2173: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
2174: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
2175: strcpy(name, name_temp);
2176: name_temp[0] = '\0';
2177:
2178: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
2179: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
2180: if(root_drive_protected == -1) {
2181: FILE *fp = NULL;
2182:
2183: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
2184: root_drive_protected = 1;
2185: try {
2186: if((fp = fopen(temp, "w")) != NULL) {
2187: if(fprintf(fp, "TEST") == 4) {
2188: root_drive_protected = 0;
2189: }
2190: }
2191: } catch(...) {
2192: }
2193: if(fp != NULL) {
2194: fclose(fp);
2195: }
2196: if(_access(temp, 0) == 0) {
2197: remove(temp);
2198: }
2199: }
2200: if(root_drive_protected == 1) {
2201: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
2202: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
2203: strcpy(tmp, msdos_combine_path(temp, name));
2204: }
2205: }
2206: }
2207: }
2208: }
1.1 root 2209: return(tmp);
2210: }
2211:
1.1.1.28 root 2212: char *msdos_get_multiple_short_path(char *src)
2213: {
1.1.1.32! root 2214: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 2215: static char env_path[ENV_SIZE];
2216: char tmp[ENV_SIZE], *token;
2217:
2218: memset(env_path, 0, sizeof(env_path));
2219: strcpy(tmp, src);
2220: token = my_strtok(tmp, ";");
2221:
2222: while(token != NULL) {
2223: if(token[0] != '\0') {
2224: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.32! root 2225: if(path != NULL && strlen(path) != 0) {
! 2226: if(env_path[0] != '\0') {
! 2227: strcat(env_path, ";");
! 2228: }
1.1.1.28 root 2229: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32! root 2230: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 2231: } else {
2232: my_strupr(short_path);
1.1.1.32! root 2233: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 2234: }
2235: }
2236: }
2237: token = my_strtok(NULL, ";");
2238: }
2239: return(env_path);
2240: }
2241:
1.1 root 2242: bool match(char *text, char *pattern)
2243: {
1.1.1.24 root 2244: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 2245: switch(*pattern) {
1.1 root 2246: case '\0':
2247: return !*text;
2248: case '*':
1.1.1.14 root 2249: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 2250: case '?':
2251: return *text && match(text + 1, pattern + 1);
2252: default:
2253: return (*text == *pattern) && match(text + 1, pattern + 1);
2254: }
2255: }
2256:
2257: bool msdos_match_volume_label(char *path, char *volume)
2258: {
2259: char *p;
2260:
1.1.1.14 root 2261: if(!*volume) {
2262: return false;
2263: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 2264: return msdos_match_volume_label(p + 1, volume);
2265: } else if((p = my_strchr(path, '\\')) != NULL) {
2266: return msdos_match_volume_label(p + 1, volume);
2267: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 2268: char tmp[MAX_PATH];
2269: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
2270: return match(volume, tmp);
1.1 root 2271: } else {
2272: return match(volume, path);
2273: }
2274: }
2275:
2276: char *msdos_fcb_path(fcb_t *fcb)
2277: {
2278: static char tmp[MAX_PATH];
2279: char name[9], ext[4];
2280:
2281: memset(name, 0, sizeof(name));
2282: memcpy(name, fcb->file_name, 8);
2283: strcpy(name, msdos_trimmed_path(name, 0));
2284:
2285: memset(ext, 0, sizeof(ext));
2286: memcpy(ext, fcb->file_name + 8, 3);
2287: strcpy(ext, msdos_trimmed_path(ext, 0));
2288:
2289: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
2290: strcpy(name, "*");
2291: }
2292: if(ext[0] == '\0') {
2293: strcpy(tmp, name);
2294: } else {
2295: if(strcmp(ext, "???") == 0) {
2296: strcpy(ext, "*");
2297: }
2298: sprintf(tmp, "%s.%s", name, ext);
2299: }
2300: return(tmp);
2301: }
2302:
2303: void msdos_set_fcb_path(fcb_t *fcb, char *path)
2304: {
2305: char *ext = my_strchr(path, '.');
2306:
2307: memset(fcb->file_name, 0x20, 8 + 3);
2308: if(ext != NULL && path[0] != '.') {
2309: *ext = '\0';
2310: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
2311: }
2312: memcpy(fcb->file_name, path, strlen(path));
2313: }
2314:
2315: char *msdos_short_path(char *path)
2316: {
2317: static char tmp[MAX_PATH];
2318:
1.1.1.24 root 2319: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
2320: strcpy(tmp, path);
2321: }
1.1 root 2322: my_strupr(tmp);
2323: return(tmp);
2324: }
2325:
1.1.1.13 root 2326: char *msdos_short_name(WIN32_FIND_DATA *fd)
2327: {
2328: static char tmp[MAX_PATH];
2329:
1.1.1.14 root 2330: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 2331: strcpy(tmp, fd->cAlternateFileName);
2332: } else {
2333: strcpy(tmp, fd->cFileName);
2334: }
2335: my_strupr(tmp);
2336: return(tmp);
2337: }
2338:
1.1 root 2339: char *msdos_short_full_path(char *path)
2340: {
2341: static char tmp[MAX_PATH];
2342: char full[MAX_PATH], *name;
2343:
1.1.1.14 root 2344: // Full works with non-existent files, but Short does not
1.1 root 2345: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 2346: *tmp = '\0';
2347: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
2348: name[-1] = '\0';
2349: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
2350: if(len == 0) {
2351: strcpy(tmp, full);
2352: } else {
2353: tmp[len++] = '\\';
2354: strcpy(tmp + len, name);
2355: }
2356: }
1.1 root 2357: my_strupr(tmp);
2358: return(tmp);
2359: }
2360:
2361: char *msdos_short_full_dir(char *path)
2362: {
2363: static char tmp[MAX_PATH];
2364: char full[MAX_PATH], *name;
2365:
2366: GetFullPathName(path, MAX_PATH, full, &name);
2367: name[-1] = '\0';
1.1.1.24 root 2368: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
2369: strcpy(tmp, full);
2370: }
1.1 root 2371: my_strupr(tmp);
2372: return(tmp);
2373: }
2374:
2375: char *msdos_local_file_path(char *path, int lfn)
2376: {
2377: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 2378: #if 0
2379: // I have forgotten the reason of this routine... :-(
1.1 root 2380: if(_access(trimmed, 0) != 0) {
2381: process_t *process = msdos_process_info_get(current_psp);
2382: static char tmp[MAX_PATH];
2383:
2384: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
2385: if(_access(tmp, 0) == 0) {
2386: return(tmp);
2387: }
2388: }
1.1.1.14 root 2389: #endif
1.1 root 2390: return(trimmed);
2391: }
2392:
1.1.1.29 root 2393: bool msdos_is_device_path(char *path)
1.1.1.11 root 2394: {
2395: char full[MAX_PATH], *name;
2396:
1.1.1.24 root 2397: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 2398: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
2399: _stricmp(full, "\\\\.\\CON" ) == 0 ||
2400: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
2401: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
2402: _stricmp(full, "\\\\.\\COM1") == 0 ||
2403: _stricmp(full, "\\\\.\\COM2") == 0 ||
2404: _stricmp(full, "\\\\.\\COM3") == 0 ||
2405: _stricmp(full, "\\\\.\\COM4") == 0 ||
2406: _stricmp(full, "\\\\.\\COM5") == 0 ||
2407: _stricmp(full, "\\\\.\\COM6") == 0 ||
2408: _stricmp(full, "\\\\.\\COM7") == 0 ||
2409: _stricmp(full, "\\\\.\\COM8") == 0 ||
2410: _stricmp(full, "\\\\.\\COM9") == 0 ||
2411: _stricmp(full, "\\\\.\\LPT1") == 0 ||
2412: _stricmp(full, "\\\\.\\LPT2") == 0 ||
2413: _stricmp(full, "\\\\.\\LPT3") == 0 ||
2414: _stricmp(full, "\\\\.\\LPT4") == 0 ||
2415: _stricmp(full, "\\\\.\\LPT5") == 0 ||
2416: _stricmp(full, "\\\\.\\LPT6") == 0 ||
2417: _stricmp(full, "\\\\.\\LPT7") == 0 ||
2418: _stricmp(full, "\\\\.\\LPT8") == 0 ||
2419: _stricmp(full, "\\\\.\\LPT9") == 0) {
2420: return(true);
2421: } else if(name != NULL) {
2422: if(_stricmp(name, "CLOCK$" ) == 0 ||
2423: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 2424: _stricmp(name, "EMMXXXX0") == 0 ||
2425: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 2426: return(true);
2427: }
2428: }
1.1.1.24 root 2429: }
2430: return(false);
1.1.1.11 root 2431: }
2432:
1.1.1.29 root 2433: bool msdos_is_con_path(char *path)
1.1.1.8 root 2434: {
1.1.1.14 root 2435: char full[MAX_PATH], *name;
1.1.1.8 root 2436:
1.1.1.24 root 2437: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 2438: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 2439: }
2440: return(false);
2441: }
2442:
1.1.1.29 root 2443: int msdos_is_comm_path(char *path)
1.1.1.24 root 2444: {
2445: char full[MAX_PATH], *name;
2446:
2447: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 2448: if(_stricmp(full, "\\\\.\\COM1") == 0) {
2449: return(1);
2450: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
2451: return(2);
2452: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
2453: return(3);
2454: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
2455: return(4);
1.1.1.24 root 2456: }
2457: }
1.1.1.29 root 2458: return(0);
2459: }
2460:
1.1.1.30 root 2461: int msdos_is_prn_path(char *path)
2462: {
2463: char full[MAX_PATH], *name;
2464:
2465: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2466: if(_stricmp(full, "\\\\.\\PRN") == 0) {
2467: return(1);
2468: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
2469: return(1);
2470: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
2471: return(2);
2472: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
2473: return(3);
2474: }
2475: }
2476: return(0);
2477: }
2478:
1.1.1.29 root 2479: char *msdos_create_comm_path(char *path, int port)
2480: {
2481: static char tmp[MAX_PATH];
2482: char *p = NULL;
2483:
2484: sprintf(tmp, "COM%d", port);
2485: if((p = strchr(path, ':')) != NULL) {
2486: strcat(tmp, p);
2487: }
2488: return(tmp);
1.1.1.24 root 2489: }
2490:
2491: bool msdos_is_existing_file(char *path)
2492: {
2493: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
2494: WIN32_FIND_DATA FindData;
2495: HANDLE hFind;
2496:
2497: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
2498: FindClose(hFind);
2499: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
2500: }
2501: return(false);
1.1.1.8 root 2502: }
2503:
1.1.1.9 root 2504: char *msdos_search_command_com(char *command_path, char *env_path)
2505: {
2506: static char tmp[MAX_PATH];
1.1.1.28 root 2507: char path[ENV_SIZE], *file_name;
1.1.1.9 root 2508:
1.1.1.28 root 2509: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 2510: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
2511: sprintf(file_name, "COMMAND.COM");
2512: if(_access(tmp, 0) == 0) {
2513: return(tmp);
2514: }
2515: }
1.1.1.28 root 2516:
2517: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 2518: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
2519: sprintf(file_name, "COMMAND.COM");
2520: if(_access(tmp, 0) == 0) {
2521: return(tmp);
2522: }
2523: }
1.1.1.28 root 2524:
2525: // check if COMMAND.COM is in the current directory
1.1.1.9 root 2526: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
2527: if(_access(tmp, 0) == 0) {
2528: return(tmp);
2529: }
2530: }
1.1.1.28 root 2531:
2532: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
2533: strcpy(path, env_path);
2534: char *token = my_strtok(path, ";");
1.1.1.9 root 2535: while(token != NULL) {
1.1.1.14 root 2536: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 2537: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
2538: if(_access(tmp, 0) == 0) {
2539: return(tmp);
2540: }
2541: }
2542: token = my_strtok(NULL, ";");
2543: }
2544: return(NULL);
2545: }
2546:
1.1.1.14 root 2547: int msdos_drive_number(const char *path)
1.1 root 2548: {
2549: char tmp[MAX_PATH], *name;
2550:
2551: GetFullPathName(path, MAX_PATH, tmp, &name);
2552: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
2553: return(tmp[0] - 'a');
2554: } else {
2555: return(tmp[0] - 'A');
2556: }
2557: }
2558:
2559: char *msdos_volume_label(char *path)
2560: {
2561: static char tmp[MAX_PATH];
2562: char volume[] = "A:\\";
2563:
2564: if(path[1] == ':') {
2565: volume[0] = path[0];
2566: } else {
2567: volume[0] = 'A' + _getdrive() - 1;
2568: }
2569: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
2570: memset(tmp, 0, sizeof(tmp));
2571: }
2572: return(tmp);
2573: }
2574:
2575: char *msdos_short_volume_label(char *label)
2576: {
2577: static char tmp[(8 + 1 + 3) + 1];
2578: char *src = label;
2579: int remain = strlen(label);
2580: char *dst_n = tmp;
2581: char *dst_e = tmp + 9;
2582:
2583: strcpy(tmp, " . ");
2584: for(int i = 0; i < 8 && remain > 0; i++) {
2585: if(msdos_lead_byte_check(*src)) {
2586: if(++i == 8) {
2587: break;
2588: }
2589: *dst_n++ = *src++;
2590: remain--;
2591: }
2592: *dst_n++ = *src++;
2593: remain--;
2594: }
2595: if(remain > 0) {
2596: for(int i = 0; i < 3 && remain > 0; i++) {
2597: if(msdos_lead_byte_check(*src)) {
2598: if(++i == 3) {
2599: break;
2600: }
2601: *dst_e++ = *src++;
2602: remain--;
2603: }
2604: *dst_e++ = *src++;
2605: remain--;
2606: }
2607: *dst_e = '\0';
2608: } else {
2609: *dst_n = '\0';
2610: }
2611: my_strupr(tmp);
2612: return(tmp);
2613: }
2614:
1.1.1.13 root 2615: errno_t msdos_maperr(unsigned long oserrno)
2616: {
2617: _doserrno = oserrno;
1.1.1.14 root 2618: switch(oserrno) {
1.1.1.13 root 2619: case ERROR_FILE_NOT_FOUND: // 2
2620: case ERROR_PATH_NOT_FOUND: // 3
2621: case ERROR_INVALID_DRIVE: // 15
2622: case ERROR_NO_MORE_FILES: // 18
2623: case ERROR_BAD_NETPATH: // 53
2624: case ERROR_BAD_NET_NAME: // 67
2625: case ERROR_BAD_PATHNAME: // 161
2626: case ERROR_FILENAME_EXCED_RANGE: // 206
2627: return ENOENT;
2628: case ERROR_TOO_MANY_OPEN_FILES: // 4
2629: return EMFILE;
2630: case ERROR_ACCESS_DENIED: // 5
2631: case ERROR_CURRENT_DIRECTORY: // 16
2632: case ERROR_NETWORK_ACCESS_DENIED: // 65
2633: case ERROR_CANNOT_MAKE: // 82
2634: case ERROR_FAIL_I24: // 83
2635: case ERROR_DRIVE_LOCKED: // 108
2636: case ERROR_SEEK_ON_DEVICE: // 132
2637: case ERROR_NOT_LOCKED: // 158
2638: case ERROR_LOCK_FAILED: // 167
2639: return EACCES;
2640: case ERROR_INVALID_HANDLE: // 6
2641: case ERROR_INVALID_TARGET_HANDLE: // 114
2642: case ERROR_DIRECT_ACCESS_HANDLE: // 130
2643: return EBADF;
2644: case ERROR_ARENA_TRASHED: // 7
2645: case ERROR_NOT_ENOUGH_MEMORY: // 8
2646: case ERROR_INVALID_BLOCK: // 9
2647: case ERROR_NOT_ENOUGH_QUOTA: // 1816
2648: return ENOMEM;
2649: case ERROR_BAD_ENVIRONMENT: // 10
2650: return E2BIG;
2651: case ERROR_BAD_FORMAT: // 11
2652: return ENOEXEC;
2653: case ERROR_NOT_SAME_DEVICE: // 17
2654: return EXDEV;
2655: case ERROR_FILE_EXISTS: // 80
2656: case ERROR_ALREADY_EXISTS: // 183
2657: return EEXIST;
2658: case ERROR_NO_PROC_SLOTS: // 89
2659: case ERROR_MAX_THRDS_REACHED: // 164
2660: case ERROR_NESTING_NOT_ALLOWED: // 215
2661: return EAGAIN;
2662: case ERROR_BROKEN_PIPE: // 109
2663: return EPIPE;
2664: case ERROR_DISK_FULL: // 112
2665: return ENOSPC;
2666: case ERROR_WAIT_NO_CHILDREN: // 128
2667: case ERROR_CHILD_NOT_COMPLETE: // 129
2668: return ECHILD;
2669: case ERROR_DIR_NOT_EMPTY: // 145
2670: return ENOTEMPTY;
2671: }
1.1.1.14 root 2672: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 2673: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
2674: return EACCES;
2675: }
1.1.1.14 root 2676: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 2677: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
2678: return ENOEXEC;
2679: }
2680: return EINVAL;
2681: }
2682:
2683: int msdos_open(const char *filename, int oflag)
2684: {
1.1.1.14 root 2685: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 2686: return _open(filename, oflag);
2687: }
1.1.1.14 root 2688:
2689: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 2690: DWORD disposition;
1.1.1.14 root 2691: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
2692: default:
1.1.1.13 root 2693: case _O_EXCL:
2694: disposition = OPEN_EXISTING;
2695: break;
2696: case _O_CREAT:
2697: disposition = OPEN_ALWAYS;
2698: break;
2699: case _O_CREAT | _O_EXCL:
2700: case _O_CREAT | _O_TRUNC | _O_EXCL:
2701: disposition = CREATE_NEW;
2702: break;
2703: case _O_TRUNC:
2704: case _O_TRUNC | _O_EXCL:
2705: disposition = TRUNCATE_EXISTING;
2706: break;
2707: case _O_CREAT | _O_TRUNC:
2708: disposition = CREATE_ALWAYS;
2709: break;
2710: }
1.1.1.14 root 2711:
1.1.1.13 root 2712: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
2713: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2714: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2715: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2716: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
2717: // Retry without FILE_WRITE_ATTRIBUTES.
2718: h = CreateFile(filename, GENERIC_READ,
2719: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2720: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2721: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2722: errno = msdos_maperr(GetLastError());
2723: return -1;
2724: }
2725: }
1.1.1.14 root 2726:
1.1.1.13 root 2727: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 2728: if(fd == -1) {
1.1.1.13 root 2729: CloseHandle(h);
2730: }
2731: return fd;
2732: }
2733:
1.1.1.14 root 2734: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 2735: {
2736: static int id = 0;
2737: char full[MAX_PATH], *name;
2738:
2739: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2740: strcpy(file_handler[fd].path, full);
2741: } else {
2742: strcpy(file_handler[fd].path, path);
2743: }
1.1.1.14 root 2744: // isatty makes no distinction between CON & NUL
2745: // GetFileSize fails on CON, succeeds on NUL
2746: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
2747: info = 0x8084;
2748: atty = 0;
2749: } else if(!atty && info == 0x80d3) {
2750: info = msdos_drive_number(".");
2751: }
1.1 root 2752: file_handler[fd].valid = 1;
2753: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
2754: file_handler[fd].atty = atty;
2755: file_handler[fd].mode = mode;
2756: file_handler[fd].info = info;
2757: file_handler[fd].psp = psp_seg;
1.1.1.21 root 2758:
2759: // init system file table
2760: if(fd < 20) {
2761: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
2762:
2763: memset(sft, 0, 0x3b);
2764:
2765: *(UINT16 *)(sft + 0x00) = 1;
2766: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
2767: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
2768: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
2769:
2770: if(!(file_handler[fd].info & 0x80)) {
2771: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
2772: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
2773:
2774: FILETIME time, local;
2775: HANDLE hHandle;
2776: WORD dos_date = 0, dos_time = 0;
2777: DWORD file_size = 0;
2778: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
2779: if(GetFileTime(hHandle, NULL, NULL, &time)) {
2780: FileTimeToLocalFileTime(&time, &local);
2781: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
2782: }
2783: file_size = GetFileSize(hHandle, NULL);
2784: }
2785: *(UINT16 *)(sft + 0x0d) = dos_time;
2786: *(UINT16 *)(sft + 0x0f) = dos_date;
2787: *(UINT32 *)(sft + 0x11) = file_size;
2788: }
2789:
2790: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
2791: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
2792: my_strupr(fname);
2793: my_strupr(ext);
2794: memset(sft + 0x20, 0x20, 11);
2795: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
2796: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
2797:
2798: *(UINT16 *)(sft + 0x31) = psp_seg;
2799: }
1.1 root 2800: }
2801:
2802: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
2803: {
2804: strcpy(file_handler[dst].path, file_handler[src].path);
2805: file_handler[dst].valid = 1;
2806: file_handler[dst].id = file_handler[src].id;
2807: file_handler[dst].atty = file_handler[src].atty;
2808: file_handler[dst].mode = file_handler[src].mode;
2809: file_handler[dst].info = file_handler[src].info;
2810: file_handler[dst].psp = psp_seg;
2811: }
2812:
1.1.1.20 root 2813: void msdos_file_handler_close(int fd)
1.1 root 2814: {
2815: file_handler[fd].valid = 0;
1.1.1.21 root 2816:
2817: if(fd < 20) {
2818: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
2819: }
1.1 root 2820: }
2821:
1.1.1.14 root 2822: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 2823: {
1.1.1.14 root 2824: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2825: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
2826: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 2827: }
2828:
2829: // find file
2830:
2831: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
2832: {
2833: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2834: return(0); // search directory only !!!
2835: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
2836: return(0);
2837: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
2838: return(0);
2839: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2840: return(0);
2841: } else if((attribute & required_mask) != required_mask) {
2842: return(0);
2843: } else {
2844: return(1);
2845: }
2846: }
2847:
1.1.1.13 root 2848: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
2849: {
1.1.1.14 root 2850: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 2851: return 1;
2852: }
2853: size_t len = strlen(fd->cFileName);
1.1.1.14 root 2854: if(len > 12) {
1.1.1.13 root 2855: return 0;
2856: }
2857: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 2858: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 2859: return 0;
2860: }
2861: return 1;
2862: }
2863:
1.1 root 2864: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
2865: {
2866: FILETIME local;
2867:
2868: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
2869: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
2870: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
2871:
2872: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
2873: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
2874: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
2875:
2876: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
2877: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
2878: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
2879: }
2880:
2881: // i/o
2882:
2883: void msdos_stdio_reopen()
2884: {
2885: if(!file_handler[0].valid) {
2886: _dup2(DUP_STDIN, 0);
2887: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
2888: }
2889: if(!file_handler[1].valid) {
2890: _dup2(DUP_STDOUT, 1);
2891: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
2892: }
2893: if(!file_handler[2].valid) {
2894: _dup2(DUP_STDERR, 2);
2895: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
2896: }
1.1.1.21 root 2897: if(!file_handler[3].valid) {
2898: _dup2(DUP_STDAUX, 3);
2899: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
2900: }
2901: if(!file_handler[4].valid) {
2902: _dup2(DUP_STDPRN, 4);
2903: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
2904: }
2905: for(int i = 0; i < 5; i++) {
2906: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
2907: msdos_psp_set_file_table(i, i, current_psp);
2908: }
2909: }
1.1 root 2910: }
2911:
2912: int msdos_kbhit()
2913: {
2914: msdos_stdio_reopen();
2915:
1.1.1.20 root 2916: process_t *process = msdos_process_info_get(current_psp);
2917: int fd = msdos_psp_get_file_table(0, current_psp);
2918:
2919: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2920: // stdin is redirected to file
1.1.1.20 root 2921: return(eof(fd) == 0);
1.1 root 2922: }
2923:
2924: // check keyboard status
1.1.1.32! root 2925: if((key_buf_char != NULL && key_buf_char->count() != 0) || key_code != 0) {
1.1 root 2926: return(1);
2927: } else {
2928: return(_kbhit());
2929: }
2930: }
2931:
2932: int msdos_getch_ex(int echo)
2933: {
2934: static char prev = 0;
2935:
2936: msdos_stdio_reopen();
2937:
1.1.1.20 root 2938: process_t *process = msdos_process_info_get(current_psp);
2939: int fd = msdos_psp_get_file_table(0, current_psp);
2940:
2941: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2942: // stdin is redirected to file
2943: retry:
2944: char data;
1.1.1.20 root 2945: if(_read(fd, &data, 1) == 1) {
1.1 root 2946: char tmp = data;
2947: if(data == 0x0a) {
2948: if(prev == 0x0d) {
2949: goto retry; // CRLF -> skip LF
2950: } else {
2951: data = 0x0d; // LF only -> CR
2952: }
2953: }
2954: prev = tmp;
2955: return(data);
2956: }
2957: return(EOF);
2958: }
2959:
2960: // input from console
1.1.1.5 root 2961: int key_char, key_scan;
2962: if(key_code != 0) {
2963: key_char = (key_code >> 0) & 0xff;
2964: key_scan = (key_code >> 8) & 0xff;
2965: key_code >>= 16;
2966: } else {
1.1.1.32! root 2967: while(key_buf_char != NULL && key_buf_char->count() == 0 && !m_halted && !ctrl_c_pressed) {
1.1.1.23 root 2968: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
2969: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
2970: if(_kbhit()) {
1.1.1.32! root 2971: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 2972: key_buf_char->write(_getch());
! 2973: key_buf_scan->write(0);
! 2974: }
1.1.1.23 root 2975: } else {
2976: Sleep(10);
2977: }
2978: } else {
2979: if(!update_key_buffer()) {
2980: Sleep(10);
2981: }
1.1.1.14 root 2982: }
2983: }
2984: if(m_halted) {
1.1.1.26 root 2985: // ctrl-break pressed - insert CR to terminate input loops
1.1.1.14 root 2986: key_char = 0x0d;
2987: key_scan = 0;
1.1.1.26 root 2988: } else if(ctrl_c_pressed) {
2989: // ctrl-c pressed
2990: key_char = 0x03;
2991: key_scan = 0;
1.1.1.32! root 2992: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.14 root 2993: key_char = key_buf_char->read();
2994: key_scan = key_buf_scan->read();
1.1.1.5 root 2995: }
1.1 root 2996: }
2997: if(echo && key_char) {
2998: msdos_putch(key_char);
2999: }
3000: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
3001: }
3002:
3003: inline int msdos_getch()
3004: {
3005: return(msdos_getch_ex(0));
3006: }
3007:
3008: inline int msdos_getche()
3009: {
3010: return(msdos_getch_ex(1));
3011: }
3012:
3013: int msdos_write(int fd, const void *buffer, unsigned int count)
3014: {
3015: static int is_cr = 0;
3016:
3017: if(fd == 1 && !file_handler[1].atty) {
3018: // CR+LF -> LF
3019: UINT8 *buf = (UINT8 *)buffer;
3020: for(unsigned int i = 0; i < count; i++) {
3021: UINT8 data = buf[i];
3022: if(is_cr) {
3023: if(data != 0x0a) {
3024: UINT8 tmp = 0x0d;
3025: _write(1, &tmp, 1);
3026: }
3027: _write(1, &data, 1);
3028: is_cr = 0;
3029: } else if(data == 0x0d) {
3030: is_cr = 1;
3031: } else {
3032: _write(1, &data, 1);
3033: }
3034: }
3035: return(count);
3036: }
1.1.1.14 root 3037: vram_flush();
1.1 root 3038: return(_write(fd, buffer, count));
3039: }
3040:
3041: void msdos_putch(UINT8 data)
3042: {
3043: static int p = 0;
3044: static int is_kanji = 0;
3045: static int is_esc = 0;
3046: static int stored_x;
3047: static int stored_y;
3048: static WORD stored_a;
1.1.1.20 root 3049: static char tmp[64], out[64];
1.1 root 3050:
3051: msdos_stdio_reopen();
3052:
1.1.1.20 root 3053: process_t *process = msdos_process_info_get(current_psp);
3054: int fd = msdos_psp_get_file_table(1, current_psp);
3055:
3056: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 3057: // stdout is redirected to file
1.1.1.20 root 3058: msdos_write(fd, &data, 1);
1.1 root 3059: return;
3060: }
1.1.1.23 root 3061: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3062:
3063: // output to console
3064: tmp[p++] = data;
3065:
1.1.1.14 root 3066: vram_flush();
3067:
1.1 root 3068: if(is_kanji) {
3069: // kanji character
3070: is_kanji = 0;
3071: } else if(is_esc) {
3072: // escape sequense
3073: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
3074: p = is_esc = 0;
3075: } else if(tmp[1] == '=' && p == 4) {
3076: COORD co;
3077: co.X = tmp[3] - 0x20;
1.1.1.14 root 3078: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 3079: SetConsoleCursorPosition(hStdout, co);
3080: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 3081: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 3082: cursor_moved = false;
3083: p = is_esc = 0;
3084: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
3085: CONSOLE_SCREEN_BUFFER_INFO csbi;
3086: COORD co;
3087: GetConsoleScreenBufferInfo(hStdout, &csbi);
3088: co.X = csbi.dwCursorPosition.X;
3089: co.Y = csbi.dwCursorPosition.Y;
3090: WORD wAttributes = csbi.wAttributes;
3091:
3092: if(tmp[1] == 'D') {
3093: co.Y++;
3094: } else if(tmp[1] == 'E') {
3095: co.X = 0;
3096: co.Y++;
3097: } else if(tmp[1] == 'M') {
3098: co.Y--;
3099: } else if(tmp[1] == '*') {
3100: SMALL_RECT rect;
1.1.1.14 root 3101: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3102: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3103: co.X = 0;
3104: co.Y = csbi.srWindow.Top;
1.1 root 3105: } else if(tmp[1] == '[') {
3106: int param[256], params = 0;
3107: memset(param, 0, sizeof(param));
3108: for(int i = 2; i < p; i++) {
3109: if(tmp[i] >= '0' && tmp[i] <= '9') {
3110: param[params] *= 10;
3111: param[params] += tmp[i] - '0';
3112: } else {
3113: params++;
3114: }
3115: }
3116: if(data == 'A') {
1.1.1.14 root 3117: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 3118: } else if(data == 'B') {
1.1.1.14 root 3119: co.Y += (params == 0) ? 1 : param[0];
1.1 root 3120: } else if(data == 'C') {
1.1.1.14 root 3121: co.X += (params == 0) ? 1 : param[0];
1.1 root 3122: } else if(data == 'D') {
1.1.1.14 root 3123: co.X -= (params == 0) ? 1 : param[0];
1.1 root 3124: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 3125: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
3126: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 3127: } else if(data == 'J') {
3128: SMALL_RECT rect;
1.1.1.14 root 3129: clear_scr_buffer(csbi.wAttributes);
1.1 root 3130: if(param[0] == 0) {
3131: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 3132: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3133: if(co.Y < csbi.srWindow.Bottom) {
3134: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3135: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3136: }
3137: } else if(param[0] == 1) {
1.1.1.14 root 3138: if(co.Y > csbi.srWindow.Top) {
3139: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
3140: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3141: }
3142: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 3143: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3144: } else if(param[0] == 2) {
1.1.1.14 root 3145: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3146: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3147: co.X = co.Y = 0;
3148: }
3149: } else if(data == 'K') {
3150: SMALL_RECT rect;
1.1.1.14 root 3151: clear_scr_buffer(csbi.wAttributes);
1.1 root 3152: if(param[0] == 0) {
3153: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 3154: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3155: } else if(param[0] == 1) {
3156: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 3157: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3158: } else if(param[0] == 2) {
3159: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 3160: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3161: }
3162: } else if(data == 'L') {
3163: SMALL_RECT rect;
1.1.1.14 root 3164: if(params == 0) {
3165: param[0] = 1;
1.1 root 3166: }
1.1.1.14 root 3167: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3168: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3169: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3170: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3171: clear_scr_buffer(csbi.wAttributes);
1.1 root 3172: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 3173: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3174: co.X = 0;
3175: } else if(data == 'M') {
3176: SMALL_RECT rect;
1.1.1.14 root 3177: if(params == 0) {
3178: param[0] = 1;
3179: }
3180: if(co.Y + param[0] > csbi.srWindow.Bottom) {
3181: clear_scr_buffer(csbi.wAttributes);
3182: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3183: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3184: } else {
1.1.1.14 root 3185: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3186: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3187: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
3188: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3189: clear_scr_buffer(csbi.wAttributes);
1.1 root 3190: }
3191: co.X = 0;
3192: } else if(data == 'h') {
3193: if(tmp[2] == '>' && tmp[3] == '5') {
3194: CONSOLE_CURSOR_INFO cur;
3195: GetConsoleCursorInfo(hStdout, &cur);
3196: if(cur.bVisible) {
3197: cur.bVisible = FALSE;
1.1.1.14 root 3198: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 3199: }
3200: }
3201: } else if(data == 'l') {
3202: if(tmp[2] == '>' && tmp[3] == '5') {
3203: CONSOLE_CURSOR_INFO cur;
3204: GetConsoleCursorInfo(hStdout, &cur);
3205: if(!cur.bVisible) {
3206: cur.bVisible = TRUE;
1.1.1.14 root 3207: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 3208: }
3209: }
3210: } else if(data == 'm') {
3211: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
3212: int reverse = 0, hidden = 0;
3213: for(int i = 0; i < params; i++) {
3214: if(param[i] == 1) {
3215: wAttributes |= FOREGROUND_INTENSITY;
3216: } else if(param[i] == 4) {
3217: wAttributes |= COMMON_LVB_UNDERSCORE;
3218: } else if(param[i] == 7) {
3219: reverse = 1;
3220: } else if(param[i] == 8 || param[i] == 16) {
3221: hidden = 1;
3222: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
3223: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
3224: if(param[i] >= 17 && param[i] <= 23) {
3225: param[i] -= 16;
3226: } else {
3227: param[i] -= 30;
3228: }
3229: if(param[i] & 1) {
3230: wAttributes |= FOREGROUND_RED;
3231: }
3232: if(param[i] & 2) {
3233: wAttributes |= FOREGROUND_GREEN;
3234: }
3235: if(param[i] & 4) {
3236: wAttributes |= FOREGROUND_BLUE;
3237: }
3238: } else if(param[i] >= 40 && param[i] <= 47) {
3239: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
3240: if((param[i] - 40) & 1) {
3241: wAttributes |= BACKGROUND_RED;
3242: }
3243: if((param[i] - 40) & 2) {
3244: wAttributes |= BACKGROUND_GREEN;
3245: }
3246: if((param[i] - 40) & 4) {
3247: wAttributes |= BACKGROUND_BLUE;
3248: }
3249: }
3250: }
3251: if(reverse) {
3252: wAttributes &= ~0xff;
3253: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
3254: }
3255: if(hidden) {
3256: wAttributes &= ~0x0f;
3257: wAttributes |= (wAttributes >> 4) & 0x0f;
3258: }
3259: } else if(data == 'n') {
3260: if(param[0] == 6) {
3261: char tmp[16];
3262: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
3263: int len = strlen(tmp);
1.1.1.32! root 3264: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 3265: for(int i = 0; i < len; i++) {
! 3266: key_buf_char->write(tmp[i]);
! 3267: key_buf_scan->write(0x00);
! 3268: }
1.1 root 3269: }
3270: }
3271: } else if(data == 's') {
3272: stored_x = co.X;
3273: stored_y = co.Y;
3274: stored_a = wAttributes;
3275: } else if(data == 'u') {
3276: co.X = stored_x;
3277: co.Y = stored_y;
3278: wAttributes = stored_a;
3279: }
3280: }
3281: if(co.X < 0) {
3282: co.X = 0;
3283: } else if(co.X >= csbi.dwSize.X) {
3284: co.X = csbi.dwSize.X - 1;
3285: }
1.1.1.14 root 3286: if(co.Y < csbi.srWindow.Top) {
3287: co.Y = csbi.srWindow.Top;
3288: } else if(co.Y > csbi.srWindow.Bottom) {
3289: co.Y = csbi.srWindow.Bottom;
1.1 root 3290: }
3291: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
3292: SetConsoleCursorPosition(hStdout, co);
3293: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 3294: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 3295: cursor_moved = false;
3296: }
3297: if(wAttributes != csbi.wAttributes) {
3298: SetConsoleTextAttribute(hStdout, wAttributes);
3299: }
3300: p = is_esc = 0;
3301: }
3302: return;
3303: } else {
3304: if(msdos_lead_byte_check(data)) {
3305: is_kanji = 1;
3306: return;
3307: } else if(data == 0x1b) {
3308: is_esc = 1;
3309: return;
3310: }
3311: }
1.1.1.20 root 3312:
3313: DWORD q = 0, num;
3314: is_kanji = 0;
3315: for(int i = 0; i < p; i++) {
3316: UINT8 c = tmp[i];
3317: if(is_kanji) {
3318: is_kanji = 0;
3319: } else if(msdos_lead_byte_check(data)) {
3320: is_kanji = 1;
3321: } else if(msdos_ctrl_code_check(data)) {
3322: out[q++] = '^';
3323: c += 'A' - 1;
3324: }
3325: out[q++] = c;
3326: }
3327: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 3328: p = 0;
1.1.1.14 root 3329:
1.1.1.15 root 3330: if(!restore_console_on_exit) {
3331: CONSOLE_SCREEN_BUFFER_INFO csbi;
3332: GetConsoleScreenBufferInfo(hStdout, &csbi);
3333: scr_top = csbi.srWindow.Top;
3334: }
1.1 root 3335: cursor_moved = true;
3336: }
3337:
3338: int msdos_aux_in()
3339: {
1.1.1.21 root 3340: msdos_stdio_reopen();
3341:
1.1.1.20 root 3342: process_t *process = msdos_process_info_get(current_psp);
3343: int fd = msdos_psp_get_file_table(3, current_psp);
3344:
3345: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 3346: char data = 0;
1.1.1.20 root 3347: _read(fd, &data, 1);
1.1 root 3348: return(data);
3349: } else {
3350: return(EOF);
3351: }
3352: }
3353:
3354: void msdos_aux_out(char data)
3355: {
1.1.1.21 root 3356: msdos_stdio_reopen();
3357:
1.1.1.20 root 3358: process_t *process = msdos_process_info_get(current_psp);
3359: int fd = msdos_psp_get_file_table(3, current_psp);
3360:
3361: if(fd < process->max_files && file_handler[fd].valid) {
3362: msdos_write(fd, &data, 1);
1.1 root 3363: }
3364: }
3365:
3366: void msdos_prn_out(char data)
3367: {
1.1.1.21 root 3368: msdos_stdio_reopen();
3369:
1.1.1.20 root 3370: process_t *process = msdos_process_info_get(current_psp);
3371: int fd = msdos_psp_get_file_table(4, current_psp);
3372:
3373: if(fd < process->max_files && file_handler[fd].valid) {
3374: msdos_write(fd, &data, 1);
1.1 root 3375: }
3376: }
3377:
3378: // memory control
3379:
1.1.1.19 root 3380: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 3381: {
3382: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3383:
3384: mcb->mz = mz;
3385: mcb->psp = psp;
1.1.1.30 root 3386: mcb->paragraphs = paragraphs;
1.1 root 3387: return(mcb);
3388: }
3389:
3390: void msdos_mcb_check(mcb_t *mcb)
3391: {
3392: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 3393: #if 0
3394: // shutdown now !!!
3395: fatalerror("broken memory control block\n");
3396: #else
3397: // return error code and continue
3398: throw(0x07); // broken memory control block
3399: #endif
1.1 root 3400: }
3401: }
3402:
3403: int msdos_mem_split(int seg, int paragraphs)
3404: {
3405: int mcb_seg = seg - 1;
3406: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3407: msdos_mcb_check(mcb);
3408:
1.1.1.30 root 3409: if(mcb->paragraphs > paragraphs) {
1.1 root 3410: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 3411: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 3412:
3413: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
3414: mcb->mz = 'M';
1.1.1.30 root 3415: mcb->paragraphs = paragraphs;
1.1 root 3416: return(0);
3417: }
3418: return(-1);
3419: }
3420:
3421: void msdos_mem_merge(int seg)
3422: {
3423: int mcb_seg = seg - 1;
3424: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3425: msdos_mcb_check(mcb);
3426:
3427: while(1) {
3428: if(mcb->mz == 'Z') {
3429: break;
3430: }
1.1.1.30 root 3431: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 3432: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
3433: msdos_mcb_check(next_mcb);
3434:
3435: if(next_mcb->psp != 0) {
3436: break;
3437: }
3438: mcb->mz = next_mcb->mz;
1.1.1.30 root 3439: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 3440: }
3441: }
3442:
1.1.1.8 root 3443: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 3444: {
3445: while(1) {
3446: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3447:
1.1.1.14 root 3448: if(mcb->psp == 0) {
3449: msdos_mem_merge(mcb_seg + 1);
3450: } else {
3451: msdos_mcb_check(mcb);
3452: }
1.1.1.8 root 3453: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.30 root 3454: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 3455: msdos_mem_split(mcb_seg + 1, paragraphs);
3456: mcb->psp = current_psp;
3457: return(mcb_seg + 1);
3458: }
3459: }
3460: if(mcb->mz == 'Z') {
3461: break;
3462: }
1.1.1.30 root 3463: mcb_seg += 1 + mcb->paragraphs;
1.1 root 3464: }
3465: return(-1);
3466: }
3467:
3468: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
3469: {
3470: int mcb_seg = seg - 1;
3471: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3472: msdos_mcb_check(mcb);
1.1.1.30 root 3473: int current_paragraphs = mcb->paragraphs;
1.1 root 3474:
3475: msdos_mem_merge(seg);
1.1.1.30 root 3476: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 3477: if(max_paragraphs) {
1.1.1.30 root 3478: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 3479: }
1.1 root 3480: msdos_mem_split(seg, current_paragraphs);
3481: return(-1);
3482: }
3483: msdos_mem_split(seg, paragraphs);
3484: return(0);
3485: }
3486:
3487: void msdos_mem_free(int seg)
3488: {
3489: int mcb_seg = seg - 1;
3490: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3491: msdos_mcb_check(mcb);
3492:
3493: mcb->psp = 0;
3494: msdos_mem_merge(seg);
3495: }
3496:
1.1.1.8 root 3497: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 3498: {
3499: int max_paragraphs = 0;
3500:
3501: while(1) {
3502: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3503: msdos_mcb_check(mcb);
3504:
1.1.1.8 root 3505: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.30 root 3506: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
3507: max_paragraphs = mcb->paragraphs;
1.1 root 3508: }
3509: }
3510: if(mcb->mz == 'Z') {
3511: break;
3512: }
1.1.1.30 root 3513: mcb_seg += 1 + mcb->paragraphs;
1.1 root 3514: }
1.1.1.14 root 3515: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 3516: }
3517:
1.1.1.8 root 3518: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
3519: {
3520: int last_seg = -1;
3521:
3522: while(1) {
3523: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3524: msdos_mcb_check(mcb);
3525:
1.1.1.14 root 3526: if(mcb->psp == psp) {
1.1.1.8 root 3527: last_seg = mcb_seg;
3528: }
1.1.1.14 root 3529: if(mcb->mz == 'Z') {
3530: break;
3531: }
1.1.1.30 root 3532: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 3533: }
3534: return(last_seg);
3535: }
3536:
1.1.1.19 root 3537: int msdos_mem_get_umb_linked()
3538: {
3539: int mcb_seg = first_mcb;
3540:
3541: while(1) {
3542: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3543: msdos_mcb_check(mcb);
3544:
3545: if(mcb->mz == 'Z') {
3546: if(mcb_seg >= (UMB_TOP >> 4)) {
3547: return(-1);
3548: }
3549: break;
3550: }
1.1.1.30 root 3551: mcb_seg += 1 + mcb->paragraphs;
1.1.1.19 root 3552: }
3553: return(0);
3554: }
3555:
3556: int msdos_mem_link_umb()
3557: {
3558: int mcb_seg = first_mcb;
3559:
3560: while(1) {
3561: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3562: msdos_mcb_check(mcb);
1.1.1.30 root 3563: mcb_seg += 1 + mcb->paragraphs;
1.1.1.19 root 3564:
3565: if(mcb->mz == 'Z') {
3566: if(mcb_seg == (MEMORY_END >> 4) - 1) {
3567: mcb->mz = 'M';
1.1.1.20 root 3568: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 3569: return(-1);
3570: }
3571: break;
3572: }
3573: }
3574: return(0);
3575: }
3576:
3577: int msdos_mem_unlink_umb()
3578: {
3579: int mcb_seg = first_mcb;
3580:
3581: while(1) {
3582: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3583: msdos_mcb_check(mcb);
1.1.1.30 root 3584: mcb_seg += 1 + mcb->paragraphs;
1.1.1.19 root 3585:
3586: if(mcb->mz == 'Z') {
3587: break;
3588: } else {
3589: if(mcb_seg == (MEMORY_END >> 4) - 1) {
3590: mcb->mz = 'Z';
1.1.1.20 root 3591: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 3592: return(-1);
3593: }
3594: }
3595: }
3596: return(0);
3597: }
3598:
1.1.1.29 root 3599: #ifdef SUPPORT_HMA
3600:
3601: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
3602: {
3603: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
3604:
3605: mcb->ms[0] = 'M';
3606: mcb->ms[1] = 'S';
3607: mcb->owner = owner;
3608: mcb->size = size;
3609: mcb->next = next;
3610: return(mcb);
3611: }
3612:
3613: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
3614: {
3615: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
3616: }
3617:
3618: int msdos_hma_mem_split(int offset, int size)
3619: {
3620: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
3621:
3622: if(!msdos_is_hma_mcb_valid(mcb)) {
3623: return(-1);
3624: }
3625: if(mcb->size >= size + 0x10) {
3626: int new_offset = offset + 0x10 + size;
3627: int new_size = mcb->size - 0x10 - size;
3628:
3629: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
3630: mcb->size = size;
3631: mcb->next = new_offset;
3632: return(0);
3633: }
3634: return(-1);
3635: }
3636:
3637: void msdos_hma_mem_merge(int offset)
3638: {
3639: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
3640:
3641: if(!msdos_is_hma_mcb_valid(mcb)) {
3642: return;
3643: }
3644: while(1) {
3645: if(mcb->next == 0) {
3646: break;
3647: }
3648: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
3649:
3650: if(!msdos_is_hma_mcb_valid(next_mcb)) {
3651: return;
3652: }
3653: if(next_mcb->owner != 0) {
3654: break;
3655: }
3656: mcb->size += 0x10 + next_mcb->size;
3657: mcb->next = next_mcb->next;
3658: }
3659: }
3660:
3661: int msdos_hma_mem_alloc(int size, UINT16 owner)
3662: {
3663: int offset = 0x10; // first mcb in HMA
3664:
3665: while(1) {
3666: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
3667:
3668: if(!msdos_is_hma_mcb_valid(mcb)) {
3669: return(-1);
3670: }
3671: if(mcb->owner == 0) {
3672: msdos_hma_mem_merge(offset);
3673: }
3674: if(mcb->owner == 0 && mcb->size >= size) {
3675: msdos_hma_mem_split(offset, size);
3676: mcb->owner = owner;
3677: return(offset);
3678: }
3679: if(mcb->next == 0) {
3680: break;
3681: }
3682: offset = mcb->next;
3683: }
3684: return(-1);
3685: }
3686:
3687: int msdos_hma_mem_realloc(int offset, int size)
3688: {
3689: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
3690:
3691: if(!msdos_is_hma_mcb_valid(mcb)) {
3692: return(-1);
3693: }
3694: if(mcb->size < size) {
3695: return(-1);
3696: }
3697: msdos_hma_mem_split(offset, size);
3698: return(0);
3699: }
3700:
3701: void msdos_hma_mem_free(int offset)
3702: {
3703: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
3704:
3705: if(!msdos_is_hma_mcb_valid(mcb)) {
3706: return;
3707: }
3708: mcb->owner = 0;
3709: msdos_hma_mem_merge(offset);
3710: }
3711:
3712: int msdos_hma_mem_get_free(int *available_offset)
3713: {
3714: int offset = 0x10; // first mcb in HMA
3715: int size = 0;
3716:
3717: while(1) {
3718: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
3719:
3720: if(!msdos_is_hma_mcb_valid(mcb)) {
3721: return(0);
3722: }
3723: if(mcb->owner == 0 && size < mcb->size) {
3724: if(available_offset != NULL) {
3725: *available_offset = offset;
3726: }
3727: size = mcb->size;
3728: }
3729: if(mcb->next == 0) {
3730: break;
3731: }
3732: offset = mcb->next;
3733: }
3734: return(size);
3735: }
3736:
3737: #endif
3738:
1.1 root 3739: // environment
3740:
3741: void msdos_env_set_argv(int env_seg, char *argv)
3742: {
3743: char *dst = (char *)(mem + (env_seg << 4));
3744:
3745: while(1) {
3746: if(dst[0] == 0) {
3747: break;
3748: }
3749: dst += strlen(dst) + 1;
3750: }
3751: *dst++ = 0; // end of environment
3752: *dst++ = 1; // top of argv[0]
3753: *dst++ = 0;
3754: memcpy(dst, argv, strlen(argv));
3755: dst += strlen(argv);
3756: *dst++ = 0;
3757: *dst++ = 0;
3758: }
3759:
3760: char *msdos_env_get_argv(int env_seg)
3761: {
3762: static char env[ENV_SIZE];
3763: char *src = env;
3764:
3765: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
3766: while(1) {
3767: if(src[0] == 0) {
3768: if(src[1] == 1) {
3769: return(src + 3);
3770: }
3771: break;
3772: }
3773: src += strlen(src) + 1;
3774: }
3775: return(NULL);
3776: }
3777:
3778: char *msdos_env_get(int env_seg, const char *name)
3779: {
3780: static char env[ENV_SIZE];
3781: char *src = env;
3782:
3783: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
3784: while(1) {
3785: if(src[0] == 0) {
3786: break;
3787: }
3788: int len = strlen(src);
3789: char *n = my_strtok(src, "=");
3790: char *v = src + strlen(n) + 1;
3791:
3792: if(_stricmp(name, n) == 0) {
3793: return(v);
3794: }
3795: src += len + 1;
3796: }
3797: return(NULL);
3798: }
3799:
3800: void msdos_env_set(int env_seg, char *name, char *value)
3801: {
3802: char env[ENV_SIZE];
3803: char *src = env;
3804: char *dst = (char *)(mem + (env_seg << 4));
3805: char *argv = msdos_env_get_argv(env_seg);
3806: int done = 0;
3807:
3808: memcpy(src, dst, ENV_SIZE);
3809: memset(dst, 0, ENV_SIZE);
3810: while(1) {
3811: if(src[0] == 0) {
3812: break;
3813: }
3814: int len = strlen(src);
3815: char *n = my_strtok(src, "=");
3816: char *v = src + strlen(n) + 1;
3817: char tmp[1024];
3818:
3819: if(_stricmp(name, n) == 0) {
3820: sprintf(tmp, "%s=%s", n, value);
3821: done = 1;
3822: } else {
3823: sprintf(tmp, "%s=%s", n, v);
3824: }
3825: memcpy(dst, tmp, strlen(tmp));
3826: dst += strlen(tmp) + 1;
3827: src += len + 1;
3828: }
3829: if(!done) {
3830: char tmp[1024];
3831:
3832: sprintf(tmp, "%s=%s", name, value);
3833: memcpy(dst, tmp, strlen(tmp));
3834: dst += strlen(tmp) + 1;
3835: }
3836: if(argv) {
3837: *dst++ = 0; // end of environment
3838: *dst++ = 1; // top of argv[0]
3839: *dst++ = 0;
3840: memcpy(dst, argv, strlen(argv));
3841: dst += strlen(argv);
3842: *dst++ = 0;
3843: *dst++ = 0;
3844: }
3845: }
3846:
3847: // process
3848:
1.1.1.8 root 3849: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 3850: {
3851: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3852:
3853: memset(psp, 0, PSP_SIZE);
3854: psp->exit[0] = 0xcd;
3855: psp->exit[1] = 0x20;
1.1.1.8 root 3856: psp->first_mcb = mcb_seg;
1.1 root 3857: psp->far_call = 0xea;
3858: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
3859: psp->cpm_entry.w.h = 0xf000;
3860: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
3861: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
3862: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
3863: psp->parent_psp = parent_psp;
1.1.1.20 root 3864: if(parent_psp == (UINT16)-1) {
3865: for(int i = 0; i < 20; i++) {
3866: if(file_handler[i].valid) {
3867: psp->file_table[i] = i;
3868: } else {
3869: psp->file_table[i] = 0xff;
3870: }
1.1 root 3871: }
1.1.1.20 root 3872: } else {
3873: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 3874: }
3875: psp->env_seg = env_seg;
3876: psp->stack.w.l = REG16(SP);
1.1.1.3 root 3877: psp->stack.w.h = SREG(SS);
1.1.1.14 root 3878: psp->file_table_size = 20;
3879: psp->file_table_ptr.w.l = 0x18;
3880: psp->file_table_ptr.w.h = psp_seg;
1.1 root 3881: psp->service[0] = 0xcd;
3882: psp->service[1] = 0x21;
3883: psp->service[2] = 0xcb;
3884: return(psp);
3885: }
3886:
1.1.1.20 root 3887: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
3888: {
3889: if(psp_seg && fd < 20) {
3890: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3891: psp->file_table[fd] = value;
3892: }
3893: }
3894:
3895: int msdos_psp_get_file_table(int fd, int psp_seg)
3896: {
3897: if(psp_seg && fd < 20) {
3898: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3899: fd = psp->file_table[fd];
3900: }
3901: return fd;
3902: }
3903:
1.1 root 3904: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
3905: {
3906: // load command file
3907: int fd = -1;
3908: int dos_command = 0;
1.1.1.24 root 3909: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 3910:
3911: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3912: int opt_len = mem[opt_ofs];
3913: memset(opt, 0, sizeof(opt));
3914: memcpy(opt, mem + opt_ofs + 1, opt_len);
3915:
1.1.1.14 root 3916: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
3917: // this is a batch file, run command.com
3918: char tmp[MAX_PATH];
3919: if(opt_len != 0) {
3920: sprintf(tmp, "/C %s %s", cmd, opt);
3921: } else {
3922: sprintf(tmp, "/C %s", cmd);
3923: }
3924: strcpy(opt, tmp);
3925: opt_len = strlen(opt);
3926: mem[opt_ofs] = opt_len;
3927: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3928: strcpy(command, comspec_path);
3929: strcpy(name_tmp, "COMMAND.COM");
3930: } else {
3931: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
3932: // redirect C:\COMMAND.COM to comspec_path
3933: strcpy(command, comspec_path);
3934: } else {
3935: strcpy(command, cmd);
3936: }
1.1.1.24 root 3937: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
3938: return(-1);
3939: }
1.1.1.14 root 3940: memset(name_tmp, 0, sizeof(name_tmp));
3941: strcpy(name_tmp, name);
3942:
3943: // check command.com
3944: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
3945: if(opt_len == 0) {
3946: // process_t *current_process = msdos_process_info_get(current_psp);
3947: process_t *current_process = NULL;
3948: for(int i = 0; i < MAX_PROCESS; i++) {
3949: if(process[i].psp == current_psp) {
3950: current_process = &process[i];
3951: break;
3952: }
3953: }
3954: if(current_process != NULL) {
3955: param->cmd_line.dw = current_process->dta.dw;
3956: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3957: opt_len = mem[opt_ofs];
3958: memset(opt, 0, sizeof(opt));
3959: memcpy(opt, mem + opt_ofs + 1, opt_len);
3960: }
3961: }
3962: for(int i = 0; i < opt_len; i++) {
3963: if(opt[i] == ' ') {
3964: continue;
3965: }
3966: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
3967: for(int j = i + 3; j < opt_len; j++) {
3968: if(opt[j] == ' ') {
3969: continue;
3970: }
3971: char *token = my_strtok(opt + j, " ");
3972:
3973: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
3974: // this is a batch file, okay to run command.com
3975: } else {
3976: // run program directly without command.com
3977: strcpy(command, token);
3978: char tmp[MAX_PATH];
3979: strcpy(tmp, token + strlen(token) + 1);
3980: strcpy(opt, tmp);
3981: opt_len = strlen(opt);
3982: mem[opt_ofs] = opt_len;
3983: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3984: dos_command = 1;
3985: }
3986: break;
1.1 root 3987: }
3988: }
1.1.1.14 root 3989: break;
1.1 root 3990: }
3991: }
3992: }
3993:
3994: // load command file
3995: strcpy(path, command);
3996: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3997: sprintf(path, "%s.COM", command);
3998: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3999: sprintf(path, "%s.EXE", command);
4000: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 4001: sprintf(path, "%s.BAT", command);
4002: if(_access(path, 0) == 0) {
4003: // this is a batch file, run command.com
4004: char tmp[MAX_PATH];
4005: if(opt_len != 0) {
4006: sprintf(tmp, "/C %s %s", path, opt);
4007: } else {
4008: sprintf(tmp, "/C %s", path);
4009: }
4010: strcpy(opt, tmp);
4011: opt_len = strlen(opt);
4012: mem[opt_ofs] = opt_len;
4013: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
4014: strcpy(path, comspec_path);
4015: strcpy(name_tmp, "COMMAND.COM");
4016: fd = _open(path, _O_RDONLY | _O_BINARY);
4017: } else {
4018: // search path in parent environments
4019: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
4020: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
4021: if(env != NULL) {
4022: char env_path[4096];
4023: strcpy(env_path, env);
4024: char *token = my_strtok(env_path, ";");
4025:
4026: while(token != NULL) {
4027: if(strlen(token) != 0) {
4028: sprintf(path, "%s", msdos_combine_path(token, command));
4029: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
4030: break;
4031: }
4032: sprintf(path, "%s.COM", msdos_combine_path(token, command));
4033: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
4034: break;
4035: }
4036: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
4037: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
4038: break;
4039: }
4040: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
4041: if(_access(path, 0) == 0) {
4042: // this is a batch file, run command.com
4043: char tmp[MAX_PATH];
4044: if(opt_len != 0) {
4045: sprintf(tmp, "/C %s %s", path, opt);
4046: } else {
4047: sprintf(tmp, "/C %s", path);
4048: }
4049: strcpy(opt, tmp);
4050: opt_len = strlen(opt);
4051: mem[opt_ofs] = opt_len;
4052: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
4053: strcpy(path, comspec_path);
4054: strcpy(name_tmp, "COMMAND.COM");
4055: fd = _open(path, _O_RDONLY | _O_BINARY);
4056: break;
4057: }
1.1.1.8 root 4058: }
1.1.1.14 root 4059: token = my_strtok(NULL, ";");
1.1 root 4060: }
4061: }
4062: }
4063: }
4064: }
4065: }
4066: if(fd == -1) {
4067: if(dos_command) {
4068: // may be dos command
4069: char tmp[MAX_PATH];
4070: sprintf(tmp, "%s %s", command, opt);
4071: system(tmp);
4072: return(0);
4073: } else {
4074: return(-1);
4075: }
4076: }
4077: _read(fd, file_buffer, sizeof(file_buffer));
4078: _close(fd);
4079:
4080: // copy environment
1.1.1.29 root 4081: int umb_linked, env_seg, psp_seg;
1.1 root 4082:
1.1.1.29 root 4083: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
4084: msdos_mem_unlink_umb();
4085: }
1.1.1.8 root 4086: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 4087: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
4088: if(umb_linked != 0) {
4089: msdos_mem_link_umb();
4090: }
4091: return(-1);
4092: }
1.1 root 4093: }
4094: if(param->env_seg == 0) {
4095: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
4096: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
4097: } else {
4098: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
4099: }
4100: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
4101:
4102: // check exe header
4103: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 4104: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 4105: UINT16 cs, ss, ip, sp;
4106:
4107: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
4108: // memory allocation
4109: int header_size = header->header_size * 16;
4110: int load_size = header->pages * 512 - header_size;
4111: if(header_size + load_size < 512) {
4112: load_size = 512 - header_size;
4113: }
4114: paragraphs = (PSP_SIZE + load_size) >> 4;
4115: if(paragraphs + header->min_alloc > free_paragraphs) {
4116: msdos_mem_free(env_seg);
4117: return(-1);
4118: }
4119: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
4120: if(paragraphs > free_paragraphs) {
4121: paragraphs = free_paragraphs;
4122: }
1.1.1.8 root 4123: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 4124: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
4125: if(umb_linked != 0) {
4126: msdos_mem_link_umb();
4127: }
4128: msdos_mem_free(env_seg);
4129: return(-1);
4130: }
1.1 root 4131: }
4132: // relocation
4133: int start_seg = psp_seg + (PSP_SIZE >> 4);
4134: for(int i = 0; i < header->relocations; i++) {
4135: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
4136: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
4137: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
4138: }
4139: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
4140: // segments
4141: cs = header->init_cs + start_seg;
4142: ss = header->init_ss + start_seg;
4143: ip = header->init_ip;
4144: sp = header->init_sp - 2; // for symdeb
4145: } else {
4146: // memory allocation
4147: paragraphs = free_paragraphs;
1.1.1.8 root 4148: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 4149: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
4150: if(umb_linked != 0) {
4151: msdos_mem_link_umb();
4152: }
4153: msdos_mem_free(env_seg);
4154: return(-1);
4155: }
1.1 root 4156: }
4157: int start_seg = psp_seg + (PSP_SIZE >> 4);
4158: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
4159: // segments
4160: cs = ss = psp_seg;
4161: ip = 0x100;
4162: sp = 0xfffe;
4163: }
1.1.1.29 root 4164: if(umb_linked != 0) {
4165: msdos_mem_link_umb();
4166: }
1.1 root 4167:
4168: // create psp
1.1.1.3 root 4169: #if defined(HAS_I386)
4170: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
4171: #else
4172: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
4173: #endif
4174: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 4175: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
4176: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
4177: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
4178: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
4179:
4180: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
4181: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
4182: mcb_psp->psp = mcb_env->psp = psp_seg;
4183:
1.1.1.4 root 4184: for(int i = 0; i < 8; i++) {
4185: if(name_tmp[i] == '.') {
4186: mcb_psp->prog_name[i] = '\0';
4187: break;
4188: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
4189: mcb_psp->prog_name[i] = name_tmp[i];
4190: i++;
4191: mcb_psp->prog_name[i] = name_tmp[i];
4192: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
4193: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
4194: } else {
4195: mcb_psp->prog_name[i] = name_tmp[i];
4196: }
4197: }
4198:
1.1 root 4199: // process info
4200: process_t *process = msdos_process_info_create(psp_seg);
4201: strcpy(process->module_dir, msdos_short_full_dir(path));
4202: process->dta.w.l = 0x80;
4203: process->dta.w.h = psp_seg;
4204: process->switchar = '/';
4205: process->max_files = 20;
4206: process->parent_int_10h_feh_called = int_10h_feh_called;
4207: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 4208: process->parent_ds = SREG(DS);
1.1.1.31 root 4209: process->parent_es = SREG(ES);
1.1 root 4210:
4211: current_psp = psp_seg;
1.1.1.23 root 4212: msdos_sda_update(current_psp);
1.1 root 4213:
4214: if(al == 0x00) {
4215: int_10h_feh_called = int_10h_ffh_called = false;
4216:
4217: // registers and segments
4218: REG16(AX) = REG16(BX) = 0x00;
4219: REG16(CX) = 0xff;
4220: REG16(DX) = psp_seg;
4221: REG16(SI) = ip;
4222: REG16(DI) = sp;
4223: REG16(SP) = sp;
1.1.1.3 root 4224: SREG(DS) = SREG(ES) = psp_seg;
4225: SREG(SS) = ss;
4226: i386_load_segment_descriptor(DS);
4227: i386_load_segment_descriptor(ES);
4228: i386_load_segment_descriptor(SS);
1.1 root 4229:
4230: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
4231: i386_jmp_far(cs, ip);
4232: } else if(al == 0x01) {
4233: // copy ss:sp and cs:ip to param block
4234: param->sp = sp;
4235: param->ss = ss;
4236: param->ip = ip;
4237: param->cs = cs;
1.1.1.31 root 4238:
4239: // the AX value to be passed to the child program is put on top of the child's stack
4240: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 4241: }
4242: return(0);
4243: }
4244:
4245: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
4246: {
4247: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
4248:
4249: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
4250: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
4251: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
4252:
1.1.1.3 root 4253: SREG(SS) = psp->stack.w.h;
4254: i386_load_segment_descriptor(SS);
1.1 root 4255: REG16(SP) = psp->stack.w.l;
4256: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
4257:
1.1.1.28 root 4258: // process_t *current_process = msdos_process_info_get(psp_seg);
4259: process_t *current_process = NULL;
4260: for(int i = 0; i < MAX_PROCESS; i++) {
4261: if(process[i].psp == psp_seg) {
4262: current_process = &process[i];
4263: break;
4264: }
4265: }
4266: if(current_process == NULL) {
4267: throw(0x1f); // general failure
4268: }
4269: int_10h_feh_called = current_process->parent_int_10h_feh_called;
4270: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
4271: if(current_process->called_by_int2eh) {
4272: REG16(AX) = ret;
4273: }
4274: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 4275: SREG(ES) = current_process->parent_es;
1.1.1.14 root 4276: i386_load_segment_descriptor(DS);
1.1.1.31 root 4277: i386_load_segment_descriptor(ES);
1.1 root 4278:
4279: if(mem_free) {
1.1.1.8 root 4280: int mcb_seg;
4281: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
4282: msdos_mem_free(mcb_seg + 1);
4283: }
4284: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
4285: msdos_mem_free(mcb_seg + 1);
4286: }
1.1 root 4287:
4288: for(int i = 0; i < MAX_FILES; i++) {
4289: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
4290: _close(i);
1.1.1.20 root 4291: msdos_file_handler_close(i);
4292: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 4293: }
4294: }
1.1.1.13 root 4295: msdos_dta_info_free(psp_seg);
1.1 root 4296: }
1.1.1.14 root 4297: msdos_stdio_reopen();
1.1 root 4298:
1.1.1.28 root 4299: memset(current_process, 0, sizeof(process_t));
1.1 root 4300:
4301: current_psp = psp->parent_psp;
4302: retval = ret;
1.1.1.23 root 4303: msdos_sda_update(current_psp);
1.1 root 4304: }
4305:
4306: // drive
4307:
4308: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
4309: {
4310: *seg = DPB_TOP >> 4;
4311: *ofs = sizeof(dpb_t) * drive_num;
4312: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
4313:
4314: if(!force_update && dpb->free_clusters != 0) {
4315: return(dpb->bytes_per_sector ? 1 : 0);
4316: }
4317: memset(dpb, 0, sizeof(dpb_t));
4318:
4319: int res = 0;
4320: char dev[64];
4321: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
4322:
1.1.1.17 root 4323: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 4324: if(hFile != INVALID_HANDLE_VALUE) {
4325: DISK_GEOMETRY geo;
4326: DWORD dwSize;
4327: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
4328: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
4329: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
4330: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 4331: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 4332: switch(geo.MediaType) {
4333: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
4334: dpb->media_type = 0xff;
4335: break;
4336: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
4337: dpb->media_type = 0xfe;
4338: break;
4339: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
4340: dpb->media_type = 0xfd;
4341: break;
4342: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
4343: dpb->media_type = 0xfc;
4344: break;
4345: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
4346: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
4347: dpb->media_type = 0xf9;
4348: break;
4349: case FixedMedia: // hard disk
4350: case RemovableMedia:
1.1.1.19 root 4351: case Unknown:
1.1 root 4352: dpb->media_type = 0xf8;
4353: break;
4354: default:
4355: dpb->media_type = 0xf0;
4356: break;
4357: }
4358: res = 1;
4359: }
4360: dpb->drive_num = drive_num;
4361: dpb->unit_num = drive_num;
4362: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
4363: dpb->next_dpb_seg = *seg;
1.1.1.14 root 4364: dpb->info_sector = 0xffff;
4365: dpb->backup_boot_sector = 0xffff;
1.1 root 4366: dpb->free_clusters = 0xffff;
1.1.1.14 root 4367: dpb->free_search_cluster = 0xffffffff;
1.1 root 4368: CloseHandle(hFile);
4369: }
4370: return(res);
4371: }
4372:
4373: // pc bios
4374:
1.1.1.19 root 4375: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
4376: {
4377: static unsigned __int64 start_msec_since_midnight = 0;
4378: static unsigned __int64 start_msec_since_hostboot = 0;
4379:
4380: if(start_msec_since_midnight == 0) {
4381: SYSTEMTIME time;
4382: GetLocalTime(&time);
4383: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
4384: start_msec_since_hostboot = cur_msec;
4385: }
4386: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
4387: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
4388: return (UINT32)tick;
4389: }
4390:
4391: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
4392: {
4393: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
4394: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
4395:
4396: if(prev_tick > next_tick) {
4397: mem[0x470] = 1;
4398: }
4399: *(UINT32 *)(mem + 0x46c) = next_tick;
4400: }
4401:
1.1.1.14 root 4402: inline void pcbios_irq0()
4403: {
4404: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 4405: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 4406: }
4407:
1.1.1.16 root 4408: int pcbios_get_text_vram_address(int page)
1.1 root 4409: {
4410: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4411: return TEXT_VRAM_TOP;
1.1 root 4412: } else {
1.1.1.14 root 4413: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 4414: }
4415: }
4416:
1.1.1.16 root 4417: int pcbios_get_shadow_buffer_address(int page)
1.1 root 4418: {
1.1.1.14 root 4419: if(!int_10h_feh_called) {
1.1.1.16 root 4420: return pcbios_get_text_vram_address(page);
1.1.1.14 root 4421: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4422: return SHADOW_BUF_TOP;
4423: } else {
1.1.1.14 root 4424: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 4425: }
4426: }
4427:
1.1.1.16 root 4428: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 4429: {
1.1.1.16 root 4430: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 4431: }
4432:
1.1.1.16 root 4433: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 4434: {
1.1.1.14 root 4435: // clear the existing screen, not just the new one
4436: int clr_height = max(height, scr_height);
4437:
1.1.1.16 root 4438: if(scr_width != width || scr_height != height) {
4439: change_console_size(width, height);
1.1.1.14 root 4440: }
4441: mem[0x462] = 0;
4442: *(UINT16 *)(mem + 0x44e) = 0;
4443:
1.1.1.16 root 4444: text_vram_top_address = pcbios_get_text_vram_address(0);
4445: text_vram_end_address = text_vram_top_address + width * height * 2;
4446: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
4447: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 4448:
1.1.1.23 root 4449: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 4450: if(clr_screen) {
1.1.1.14 root 4451: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
4452: mem[ofs++] = 0x20;
4453: mem[ofs++] = 0x07;
4454: }
4455:
4456: EnterCriticalSection(&vram_crit_sect);
4457: for(int y = 0; y < clr_height; y++) {
4458: for(int x = 0; x < scr_width; x++) {
4459: SCR_BUF(y,x).Char.AsciiChar = ' ';
4460: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 4461: }
4462: }
4463: SMALL_RECT rect;
1.1.1.14 root 4464: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
4465: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4466: vram_length_char = vram_last_length_char = 0;
4467: vram_length_attr = vram_last_length_attr = 0;
4468: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4469: }
1.1.1.14 root 4470: COORD co;
4471: co.X = 0;
4472: co.Y = scr_top;
4473: SetConsoleCursorPosition(hStdout, co);
4474: cursor_moved = true;
4475: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 4476: }
4477:
1.1.1.16 root 4478: inline void pcbios_int_10h_00h()
4479: {
4480: switch(REG8(AL) & 0x7f) {
4481: case 0x70: // v-text mode
4482: case 0x71: // extended cga v-text mode
4483: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
4484: break;
4485: default:
4486: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
4487: break;
4488: }
4489: if(REG8(AL) & 0x80) {
4490: mem[0x487] |= 0x80;
4491: } else {
4492: mem[0x487] &= ~0x80;
4493: }
4494: mem[0x449] = REG8(AL) & 0x7f;
4495: }
4496:
1.1 root 4497: inline void pcbios_int_10h_01h()
4498: {
1.1.1.13 root 4499: mem[0x460] = REG8(CL);
4500: mem[0x461] = REG8(CH);
1.1.1.14 root 4501:
1.1.1.23 root 4502: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4503: CONSOLE_CURSOR_INFO ci;
4504: GetConsoleCursorInfo(hStdout, &ci);
4505: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
4506: // if(ci.bVisible) {
4507: int lines = max(8, REG8(CL) + 1);
4508: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
4509: // }
4510: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 4511: }
4512:
4513: inline void pcbios_int_10h_02h()
4514: {
1.1.1.14 root 4515: // continuously setting the cursor effectively stops it blinking
4516: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 4517: COORD co;
4518: co.X = REG8(DL);
1.1.1.14 root 4519: co.Y = REG8(DH) + scr_top;
4520:
4521: // some programs hide the cursor by moving it off screen
4522: static bool hidden = false;
1.1.1.23 root 4523: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4524: CONSOLE_CURSOR_INFO ci;
4525: GetConsoleCursorInfo(hStdout, &ci);
4526:
4527: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
4528: if(ci.bVisible) {
4529: ci.bVisible = FALSE;
4530: // SetConsoleCursorInfo(hStdout, &ci);
4531: hidden = true;
4532: }
4533: } else if(hidden) {
4534: if(!ci.bVisible) {
4535: ci.bVisible = TRUE;
4536: // SetConsoleCursorInfo(hStdout, &ci);
4537: }
4538: hidden = false;
4539: }
1.1 root 4540: }
1.1.1.14 root 4541: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
4542: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 4543: }
4544:
4545: inline void pcbios_int_10h_03h()
4546: {
1.1.1.14 root 4547: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4548: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 4549: REG8(CL) = mem[0x460];
4550: REG8(CH) = mem[0x461];
4551: }
4552:
4553: inline void pcbios_int_10h_05h()
4554: {
1.1.1.14 root 4555: if(REG8(AL) >= vram_pages) {
4556: return;
4557: }
4558: if(mem[0x462] != REG8(AL)) {
4559: vram_flush();
4560:
1.1.1.23 root 4561: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4562: SMALL_RECT rect;
1.1.1.14 root 4563: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
4564: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4565:
1.1.1.16 root 4566: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 4567: for(int x = 0; x < scr_width; x++) {
4568: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
4569: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 4570: }
4571: }
1.1.1.16 root 4572: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 4573: for(int x = 0; x < scr_width; x++) {
4574: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
4575: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 4576: }
4577: }
1.1.1.14 root 4578: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4579:
4580: COORD co;
1.1.1.14 root 4581: co.X = mem[0x450 + REG8(AL) * 2];
4582: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
4583: if(co.Y < scr_top + scr_height) {
4584: SetConsoleCursorPosition(hStdout, co);
4585: }
1.1 root 4586: }
1.1.1.14 root 4587: mem[0x462] = REG8(AL);
4588: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
4589: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 4590: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 4591: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 4592: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 4593: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 4594: }
4595:
4596: inline void pcbios_int_10h_06h()
4597: {
1.1.1.14 root 4598: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
4599: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
4600: return;
4601: }
4602: vram_flush();
4603:
1.1.1.23 root 4604: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4605: SMALL_RECT rect;
1.1.1.14 root 4606: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
4607: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4608:
4609: int right = min(REG8(DL), scr_width - 1);
4610: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 4611:
4612: if(REG8(AL) == 0) {
1.1.1.14 root 4613: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 4614: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4615: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
4616: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4617: }
4618: }
4619: } else {
1.1.1.14 root 4620: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 4621: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4622: if(y2 <= bottom) {
4623: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 4624: } else {
1.1.1.14 root 4625: SCR_BUF(y,x).Char.AsciiChar = ' ';
4626: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4627: }
1.1.1.14 root 4628: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
4629: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 4630: }
4631: }
4632: }
1.1.1.14 root 4633: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4634: }
4635:
4636: inline void pcbios_int_10h_07h()
4637: {
1.1.1.14 root 4638: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
4639: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
4640: return;
4641: }
4642: vram_flush();
4643:
1.1.1.23 root 4644: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4645: SMALL_RECT rect;
1.1.1.14 root 4646: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
4647: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4648:
4649: int right = min(REG8(DL), scr_width - 1);
4650: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 4651:
4652: if(REG8(AL) == 0) {
1.1.1.14 root 4653: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 4654: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4655: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
4656: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4657: }
4658: }
4659: } else {
1.1.1.14 root 4660: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 4661: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4662: if(y2 >= REG8(CH)) {
4663: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 4664: } else {
1.1.1.14 root 4665: SCR_BUF(y,x).Char.AsciiChar = ' ';
4666: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4667: }
1.1.1.14 root 4668: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
4669: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 4670: }
4671: }
4672: }
1.1.1.14 root 4673: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4674: }
4675:
4676: inline void pcbios_int_10h_08h()
4677: {
4678: COORD co;
4679: DWORD num;
4680:
1.1.1.14 root 4681: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4682: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 4683:
4684: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4685: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4686: co.Y += scr_top;
4687: vram_flush();
1.1 root 4688: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
4689: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
4690: REG8(AL) = scr_char[0];
4691: REG8(AH) = scr_attr[0];
4692: } else {
1.1.1.16 root 4693: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 4694: }
4695: }
4696:
4697: inline void pcbios_int_10h_09h()
4698: {
4699: COORD co;
4700:
1.1.1.14 root 4701: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4702: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4703:
1.1.1.16 root 4704: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
4705: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 4706:
4707: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 4708: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4709: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4710: while(dest < end) {
4711: write_text_vram_char(dest - vram, REG8(AL));
4712: mem[dest++] = REG8(AL);
4713: write_text_vram_attr(dest - vram, REG8(BL));
4714: mem[dest++] = REG8(BL);
1.1 root 4715: }
1.1.1.14 root 4716: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4717: } else {
1.1.1.14 root 4718: while(dest < end) {
1.1 root 4719: mem[dest++] = REG8(AL);
4720: mem[dest++] = REG8(BL);
4721: }
4722: }
4723: }
4724:
4725: inline void pcbios_int_10h_0ah()
4726: {
4727: COORD co;
4728:
1.1.1.14 root 4729: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4730: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4731:
1.1.1.16 root 4732: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
4733: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 4734:
4735: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 4736: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4737: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4738: while(dest < end) {
4739: write_text_vram_char(dest - vram, REG8(AL));
4740: mem[dest++] = REG8(AL);
4741: dest++;
1.1 root 4742: }
1.1.1.14 root 4743: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4744: } else {
1.1.1.14 root 4745: while(dest < end) {
1.1 root 4746: mem[dest++] = REG8(AL);
4747: dest++;
4748: }
4749: }
4750: }
4751:
4752: inline void pcbios_int_10h_0eh()
4753: {
1.1.1.14 root 4754: DWORD num;
4755: COORD co;
4756:
4757: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4758: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4759:
4760: if(REG8(AL) == 7) {
4761: //MessageBeep(-1);
4762: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
4763: if(REG8(AL) == 10) {
4764: vram_flush();
4765: }
1.1.1.23 root 4766: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 4767: cursor_moved = true;
4768: } else {
1.1.1.16 root 4769: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 4770: if(mem[0x462] == REG8(BH)) {
4771: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4772: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4773: write_text_vram_char(dest - vram, REG8(AL));
4774: LeaveCriticalSection(&vram_crit_sect);
4775:
1.1.1.23 root 4776: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4777: if(++co.X == scr_width) {
4778: co.X = 0;
4779: if(++co.Y == scr_height) {
4780: vram_flush();
4781: WriteConsole(hStdout, "\n", 1, &num, NULL);
4782: cursor_moved = true;
4783: }
4784: }
4785: if(!cursor_moved) {
4786: co.Y += scr_top;
4787: SetConsoleCursorPosition(hStdout, co);
4788: cursor_moved = true;
4789: }
4790: }
4791: mem[dest] = REG8(AL);
4792: }
1.1 root 4793: }
4794:
4795: inline void pcbios_int_10h_0fh()
4796: {
4797: REG8(AL) = mem[0x449];
4798: REG8(AH) = mem[0x44a];
4799: REG8(BH) = mem[0x462];
4800: }
4801:
1.1.1.14 root 4802: inline void pcbios_int_10h_11h()
4803: {
4804: switch(REG8(AL)) {
1.1.1.16 root 4805: case 0x01:
1.1.1.14 root 4806: case 0x11:
1.1.1.16 root 4807: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 4808: break;
1.1.1.16 root 4809: case 0x02:
1.1.1.14 root 4810: case 0x12:
1.1.1.16 root 4811: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 4812: break;
1.1.1.16 root 4813: case 0x04:
1.1.1.14 root 4814: case 0x14:
1.1.1.16 root 4815: pcbios_set_console_size(80, 25, true);
4816: break;
4817: case 0x18:
4818: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 4819: break;
4820: case 0x30:
4821: SREG(ES) = 0;
4822: i386_load_segment_descriptor(ES);
4823: REG16(BP) = 0;
4824: REG16(CX) = mem[0x485];
4825: REG8(DL) = mem[0x484];
4826: break;
4827: }
4828: }
4829:
4830: inline void pcbios_int_10h_12h()
4831: {
1.1.1.16 root 4832: switch(REG8(BL)) {
4833: case 0x10:
1.1.1.14 root 4834: REG16(BX) = 0x0003;
4835: REG16(CX) = 0x0009;
1.1.1.16 root 4836: break;
1.1.1.14 root 4837: }
4838: }
4839:
1.1 root 4840: inline void pcbios_int_10h_13h()
4841: {
1.1.1.3 root 4842: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 4843: COORD co;
4844: DWORD num;
4845:
4846: co.X = REG8(DL);
1.1.1.14 root 4847: co.Y = REG8(DH) + scr_top;
4848:
4849: vram_flush();
1.1 root 4850:
4851: switch(REG8(AL)) {
4852: case 0x00:
4853: case 0x01:
4854: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4855: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4856: CONSOLE_SCREEN_BUFFER_INFO csbi;
4857: GetConsoleScreenBufferInfo(hStdout, &csbi);
4858: SetConsoleCursorPosition(hStdout, co);
4859:
4860: if(csbi.wAttributes != REG8(BL)) {
4861: SetConsoleTextAttribute(hStdout, REG8(BL));
4862: }
1.1.1.14 root 4863: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
4864:
1.1 root 4865: if(csbi.wAttributes != REG8(BL)) {
4866: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
4867: }
4868: if(REG8(AL) == 0x00) {
1.1.1.15 root 4869: if(!restore_console_on_exit) {
4870: GetConsoleScreenBufferInfo(hStdout, &csbi);
4871: scr_top = csbi.srWindow.Top;
4872: }
1.1.1.14 root 4873: co.X = mem[0x450 + REG8(BH) * 2];
4874: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 4875: SetConsoleCursorPosition(hStdout, co);
4876: } else {
4877: cursor_moved = true;
4878: }
4879: } else {
1.1.1.3 root 4880: m_CF = 1;
1.1 root 4881: }
4882: break;
4883: case 0x02:
4884: case 0x03:
4885: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4886: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4887: CONSOLE_SCREEN_BUFFER_INFO csbi;
4888: GetConsoleScreenBufferInfo(hStdout, &csbi);
4889: SetConsoleCursorPosition(hStdout, co);
4890:
4891: WORD wAttributes = csbi.wAttributes;
4892: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
4893: if(wAttributes != mem[ofs + 1]) {
4894: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
4895: wAttributes = mem[ofs + 1];
4896: }
1.1.1.14 root 4897: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 4898: }
4899: if(csbi.wAttributes != wAttributes) {
4900: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
4901: }
4902: if(REG8(AL) == 0x02) {
1.1.1.14 root 4903: co.X = mem[0x450 + REG8(BH) * 2];
4904: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 4905: SetConsoleCursorPosition(hStdout, co);
4906: } else {
4907: cursor_moved = true;
4908: }
4909: } else {
1.1.1.3 root 4910: m_CF = 1;
1.1 root 4911: }
4912: break;
4913: case 0x10:
4914: case 0x11:
4915: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4916: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4917: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
4918: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
4919: for(int i = 0; i < num; i++) {
4920: mem[ofs++] = scr_char[i];
4921: mem[ofs++] = scr_attr[i];
4922: if(REG8(AL) == 0x11) {
4923: mem[ofs++] = 0;
4924: mem[ofs++] = 0;
4925: }
4926: }
4927: } else {
1.1.1.16 root 4928: 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 4929: mem[ofs++] = mem[src++];
4930: mem[ofs++] = mem[src++];
4931: if(REG8(AL) == 0x11) {
4932: mem[ofs++] = 0;
4933: mem[ofs++] = 0;
4934: }
1.1.1.14 root 4935: if(++co.X == scr_width) {
4936: if(++co.Y == scr_height) {
1.1 root 4937: break;
4938: }
4939: co.X = 0;
4940: }
4941: }
4942: }
4943: break;
4944: case 0x20:
4945: case 0x21:
4946: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4947: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4948: int len = min(REG16(CX), scr_width * scr_height);
4949: for(int i = 0; i < len; i++) {
1.1 root 4950: scr_char[i] = mem[ofs++];
4951: scr_attr[i] = mem[ofs++];
4952: if(REG8(AL) == 0x21) {
4953: ofs += 2;
4954: }
4955: }
1.1.1.14 root 4956: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4957: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4958: } else {
1.1.1.16 root 4959: 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 4960: mem[dest++] = mem[ofs++];
4961: mem[dest++] = mem[ofs++];
4962: if(REG8(AL) == 0x21) {
4963: ofs += 2;
4964: }
1.1.1.14 root 4965: if(++co.X == scr_width) {
4966: if(++co.Y == scr_height) {
1.1 root 4967: break;
4968: }
4969: co.X = 0;
4970: }
4971: }
4972: }
4973: break;
4974: default:
1.1.1.22 root 4975: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 4976: m_CF = 1;
1.1 root 4977: break;
4978: }
4979: }
4980:
1.1.1.30 root 4981: inline void pcbios_int_10h_18h()
4982: {
4983: switch(REG8(AL)) {
4984: case 0x00:
4985: case 0x01:
4986: // REG8(AL) = 0x86;
4987: REG8(AL) = 0x00;
4988: break;
4989: default:
4990: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
4991: m_CF = 1;
4992: break;
4993: }
4994: }
4995:
1.1.1.14 root 4996: inline void pcbios_int_10h_1ah()
4997: {
4998: switch(REG8(AL)) {
4999: case 0x00:
5000: REG8(AL) = 0x1a;
5001: REG8(BL) = 0x08;
5002: REG8(BH) = 0x00;
5003: break;
5004: default:
1.1.1.22 root 5005: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 5006: m_CF = 1;
5007: break;
5008: }
5009: }
5010:
1.1 root 5011: inline void pcbios_int_10h_1dh()
5012: {
5013: switch(REG8(AL)) {
5014: case 0x01:
5015: break;
5016: case 0x02:
5017: REG16(BX) = 0;
5018: break;
5019: default:
1.1.1.22 root 5020: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5021: m_CF = 1;
5022: break;
5023: }
5024: }
5025:
5026: inline void pcbios_int_10h_4fh()
5027: {
5028: switch(REG8(AL)) {
5029: case 0x00:
5030: REG8(AH) = 0x02; // not supported
5031: break;
5032: case 0x01:
5033: case 0x02:
5034: case 0x03:
5035: case 0x04:
5036: case 0x05:
5037: case 0x06:
5038: case 0x07:
5039: case 0x08:
5040: case 0x09:
5041: case 0x0a:
5042: case 0x0b:
5043: case 0x0c:
5044: REG8(AH) = 0x01; // failed
5045: break;
5046: default:
5047: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 5048: m_CF = 1;
1.1 root 5049: break;
5050: }
5051: }
5052:
5053: inline void pcbios_int_10h_82h()
5054: {
5055: static UINT8 mode = 0;
5056:
5057: switch(REG8(AL)) {
1.1.1.22 root 5058: case 0x00:
1.1 root 5059: if(REG8(BL) != 0xff) {
5060: mode = REG8(BL);
5061: }
5062: REG8(AL) = mode;
5063: break;
5064: default:
1.1.1.22 root 5065: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 5066: m_CF = 1;
1.1 root 5067: break;
5068: }
5069: }
5070:
1.1.1.22 root 5071: inline void pcbios_int_10h_83h()
5072: {
5073: static UINT8 mode = 0;
5074:
5075: switch(REG8(AL)) {
5076: case 0x00:
5077: REG16(AX) = 0; // offset???
5078: SREG(ES) = (SHADOW_BUF_TOP >> 4);
5079: i386_load_segment_descriptor(ES);
5080: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
5081: break;
5082: default:
5083: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5084: m_CF = 1;
5085: break;
5086: }
5087: }
5088:
5089: inline void pcbios_int_10h_90h()
5090: {
5091: REG8(AL) = mem[0x449];
5092: }
5093:
5094: inline void pcbios_int_10h_91h()
5095: {
5096: REG8(AL) = 0x04; // VGA
5097: }
5098:
5099: inline void pcbios_int_10h_efh()
5100: {
5101: REG16(DX) = 0xffff;
5102: }
5103:
1.1 root 5104: inline void pcbios_int_10h_feh()
5105: {
5106: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 5107: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 5108: i386_load_segment_descriptor(ES);
1.1.1.8 root 5109: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 5110: }
5111: int_10h_feh_called = true;
5112: }
5113:
5114: inline void pcbios_int_10h_ffh()
5115: {
5116: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 5117: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 5118: COORD co;
5119: DWORD num;
5120:
1.1.1.14 root 5121: vram_flush();
5122:
5123: co.X = (REG16(DI) >> 1) % scr_width;
5124: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 5125: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
5126: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 5127: int len;
5128: for(len = 0; ofs < end; len++) {
5129: scr_char[len] = mem[ofs++];
5130: scr_attr[len] = mem[ofs++];
5131: }
5132: co.Y += scr_top;
5133: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
5134: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 5135: }
5136: int_10h_ffh_called = true;
5137: }
5138:
1.1.1.25 root 5139: inline void pcbios_int_14h_00h()
5140: {
1.1.1.29 root 5141: if(REG16(DX) < 4) {
1.1.1.25 root 5142: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
5143: UINT8 selector = sio_read(REG16(DX), 3);
5144: selector &= ~0x3f;
5145: selector |= REG8(AL) & 0x1f;
5146: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
5147: sio_write(REG16(DX), 3, selector | 0x80);
5148: sio_write(REG16(DX), 0, divisor & 0xff);
5149: sio_write(REG16(DX), 1, divisor >> 8);
5150: sio_write(REG16(DX), 3, selector);
5151: REG8(AH) = sio_read(REG16(DX), 5);
5152: REG8(AL) = sio_read(REG16(DX), 6);
5153: } else {
5154: REG8(AH) = 0x80;
5155: }
5156: }
5157:
5158: inline void pcbios_int_14h_01h()
5159: {
1.1.1.29 root 5160: if(REG16(DX) < 4) {
1.1.1.25 root 5161: UINT8 selector = sio_read(REG16(DX), 3);
5162: sio_write(REG16(DX), 3, selector & ~0x80);
5163: sio_write(REG16(DX), 0, REG8(AL));
5164: sio_write(REG16(DX), 3, selector);
5165: REG8(AH) = sio_read(REG16(DX), 5);
5166: } else {
5167: REG8(AH) = 0x80;
5168: }
5169: }
5170:
5171: inline void pcbios_int_14h_02h()
5172: {
1.1.1.29 root 5173: if(REG16(DX) < 4) {
1.1.1.25 root 5174: UINT8 selector = sio_read(REG16(DX), 3);
5175: sio_write(REG16(DX), 3, selector & ~0x80);
5176: REG8(AL) = sio_read(REG16(DX), 0);
5177: sio_write(REG16(DX), 3, selector);
5178: REG8(AH) = sio_read(REG16(DX), 5);
5179: } else {
5180: REG8(AH) = 0x80;
5181: }
5182: }
5183:
5184: inline void pcbios_int_14h_03h()
5185: {
1.1.1.29 root 5186: if(REG16(DX) < 4) {
1.1.1.25 root 5187: REG8(AH) = sio_read(REG16(DX), 5);
5188: REG8(AL) = sio_read(REG16(DX), 6);
5189: } else {
5190: REG8(AH) = 0x80;
5191: }
5192: }
5193:
5194: inline void pcbios_int_14h_04h()
5195: {
1.1.1.29 root 5196: if(REG16(DX) < 4) {
1.1.1.25 root 5197: UINT8 selector = sio_read(REG16(DX), 3);
5198: if(REG8(CH) <= 0x03) {
5199: selector = (selector & ~0x03) | REG8(CH);
5200: }
5201: if(REG8(BL) == 0x00) {
5202: selector &= ~0x04;
5203: } else if(REG8(BL) == 0x01) {
5204: selector |= 0x04;
5205: }
5206: if(REG8(BH) == 0x00) {
5207: selector = (selector & ~0x38) | 0x00;
5208: } else if(REG8(BH) == 0x01) {
5209: selector = (selector & ~0x38) | 0x08;
5210: } else if(REG8(BH) == 0x02) {
5211: selector = (selector & ~0x38) | 0x18;
5212: } else if(REG8(BH) == 0x03) {
5213: selector = (selector & ~0x38) | 0x28;
5214: } else if(REG8(BH) == 0x04) {
5215: selector = (selector & ~0x38) | 0x38;
5216: }
5217: if(REG8(AL) == 0x00) {
5218: selector |= 0x40;
5219: } else if(REG8(AL) == 0x01) {
5220: selector &= ~0x40;
5221: }
5222: if(REG8(CL) <= 0x0b) {
5223: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
5224: UINT16 divisor = 115200 / rate[REG8(CL)];
5225: sio_write(REG16(DX), 3, selector | 0x80);
5226: sio_write(REG16(DX), 0, divisor & 0xff);
5227: sio_write(REG16(DX), 1, divisor >> 8);
5228: }
5229: sio_write(REG16(DX), 3, selector);
5230: REG8(AH) = sio_read(REG16(DX), 5);
5231: REG8(AL) = sio_read(REG16(DX), 6);
5232: } else {
5233: REG8(AH) = 0x80;
5234: }
5235: }
5236:
5237: inline void pcbios_int_14h_05h()
5238: {
1.1.1.29 root 5239: if(REG16(DX) < 4) {
1.1.1.25 root 5240: if(REG8(AL) == 0x00) {
5241: REG8(BL) = sio_read(REG16(DX), 4);
5242: REG8(AH) = sio_read(REG16(DX), 5);
5243: REG8(AL) = sio_read(REG16(DX), 6);
5244: } else if(REG8(AL) == 0x01) {
5245: sio_write(REG16(DX), 4, REG8(BL));
5246: REG8(AH) = sio_read(REG16(DX), 5);
5247: REG8(AL) = sio_read(REG16(DX), 6);
5248: } else {
5249: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x14, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5250: }
5251: } else {
5252: REG8(AH) = 0x80;
5253: }
5254: }
5255:
1.1.1.14 root 5256: inline void pcbios_int_15h_10h()
5257: {
1.1.1.22 root 5258: switch(REG8(AL)) {
5259: case 0x00:
1.1.1.14 root 5260: Sleep(10);
5261: hardware_update();
1.1.1.22 root 5262: break;
5263: default:
5264: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 5265: REG8(AH) = 0x86;
5266: m_CF = 1;
5267: }
5268: }
5269:
1.1 root 5270: inline void pcbios_int_15h_23h()
5271: {
5272: switch(REG8(AL)) {
1.1.1.22 root 5273: case 0x00:
1.1.1.8 root 5274: REG8(CL) = cmos_read(0x2d);
5275: REG8(CH) = cmos_read(0x2e);
1.1 root 5276: break;
1.1.1.22 root 5277: case 0x01:
1.1.1.8 root 5278: cmos_write(0x2d, REG8(CL));
5279: cmos_write(0x2e, REG8(CH));
1.1 root 5280: break;
5281: default:
1.1.1.22 root 5282: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 5283: REG8(AH) = 0x86;
1.1.1.3 root 5284: m_CF = 1;
1.1 root 5285: break;
5286: }
5287: }
5288:
5289: inline void pcbios_int_15h_24h()
5290: {
5291: switch(REG8(AL)) {
1.1.1.22 root 5292: case 0x00:
1.1.1.3 root 5293: i386_set_a20_line(0);
1.1 root 5294: REG8(AH) = 0;
5295: break;
1.1.1.22 root 5296: case 0x01:
1.1.1.3 root 5297: i386_set_a20_line(1);
1.1 root 5298: REG8(AH) = 0;
5299: break;
1.1.1.22 root 5300: case 0x02:
1.1 root 5301: REG8(AH) = 0;
1.1.1.3 root 5302: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 5303: REG16(CX) = 0;
5304: break;
1.1.1.22 root 5305: case 0x03:
1.1 root 5306: REG16(AX) = 0;
5307: REG16(BX) = 0;
5308: break;
1.1.1.22 root 5309: default:
5310: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5311: REG8(AH) = 0x86;
5312: m_CF = 1;
5313: break;
1.1 root 5314: }
5315: }
5316:
5317: inline void pcbios_int_15h_49h()
5318: {
1.1.1.27 root 5319: REG8(AH) = 0x00;
5320: REG8(BL) = 0x00; // DOS/V
1.1 root 5321: }
5322:
1.1.1.22 root 5323: inline void pcbios_int_15h_50h()
5324: {
5325: switch(REG8(AL)) {
5326: case 0x00:
5327: case 0x01:
5328: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
5329: REG8(AH) = 0x01; // invalid font type in bh
5330: m_CF = 1;
1.1.1.27 root 5331: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 5332: REG8(AH) = 0x02; // bl not zero
5333: m_CF = 1;
5334: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
5335: REG8(AH) = 0x04; // invalid code page
5336: m_CF = 1;
1.1.1.27 root 5337: } else if(REG8(AL) == 0x01) {
5338: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 5339: m_CF = 1;
1.1.1.27 root 5340: } else {
5341: // dummy font read routine is at fffd:000d
5342: SREG(ES) = 0xfffd;
5343: i386_load_segment_descriptor(ES);
1.1.1.32! root 5344: REG16(BX) = 0x000d;
1.1.1.27 root 5345: REG8(AH) = 0x00; // success
1.1.1.22 root 5346: }
5347: break;
5348: default:
5349: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5350: REG8(AH) = 0x86;
5351: m_CF = 1;
5352: break;
5353: }
5354: }
5355:
1.1.1.30 root 5356: inline void pcbios_int_15h_53h()
5357: {
5358: switch(REG8(AL)) {
5359: case 0x00:
5360: // APM is not installed
5361: REG8(AH) = 0x86;
5362: m_CF = 1;
5363: break;
5364: default:
5365: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5366: REG8(AH) = 0x86;
5367: m_CF = 1;
5368: break;
5369: }
5370: }
5371:
1.1 root 5372: inline void pcbios_int_15h_86h()
5373: {
5374: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 5375: UINT32 msec = usec / 1000;
5376:
5377: while(msec) {
5378: UINT32 tmp = min(msec, 100);
5379: if(msec - tmp < 10) {
5380: tmp = msec;
5381: }
5382: Sleep(tmp);
5383:
5384: if(m_halted) {
5385: return;
5386: }
5387: msec -= tmp;
5388: }
1.1 root 5389: }
5390:
5391: inline void pcbios_int_15h_87h()
5392: {
5393: // copy extended memory (from DOSBox)
5394: int len = REG16(CX) * 2;
1.1.1.3 root 5395: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 5396: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
5397: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
5398: memcpy(mem + dst, mem + src, len);
5399: REG16(AX) = 0x00;
5400: }
5401:
5402: inline void pcbios_int_15h_88h()
5403: {
1.1.1.17 root 5404: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 5405: }
5406:
5407: inline void pcbios_int_15h_89h()
5408: {
1.1.1.21 root 5409: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 5410: // switch to protected mode (from DOSBox)
5411: write_io_byte(0x20, 0x10);
5412: write_io_byte(0x21, REG8(BH));
5413: write_io_byte(0x21, 0x00);
5414: write_io_byte(0xa0, 0x10);
5415: write_io_byte(0xa1, REG8(BL));
5416: write_io_byte(0xa1, 0x00);
1.1.1.3 root 5417: i386_set_a20_line(1);
5418: int ofs = SREG_BASE(ES) + REG16(SI);
5419: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
5420: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
5421: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
5422: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
5423: #if defined(HAS_I386)
5424: m_cr[0] |= 1;
5425: #else
5426: m_msw |= 1;
5427: #endif
5428: SREG(DS) = 0x18;
5429: SREG(ES) = 0x20;
5430: SREG(SS) = 0x28;
5431: i386_load_segment_descriptor(DS);
5432: i386_load_segment_descriptor(ES);
5433: i386_load_segment_descriptor(SS);
1.1.1.21 root 5434: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 5435: REG16(SP) += 6;
1.1.1.3 root 5436: #if defined(HAS_I386)
1.1.1.21 root 5437: UINT32 flags = get_flags();
5438: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
5439: set_flags(flags);
1.1.1.3 root 5440: #else
1.1.1.21 root 5441: UINT32 flags = CompressFlags();
5442: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
5443: ExpandFlags(flags);
1.1.1.3 root 5444: #endif
1.1 root 5445: REG16(AX) = 0x00;
1.1.1.21 root 5446: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 5447: #else
1.1.1.21 root 5448: // i86/i186/v30: protected mode is not supported
1.1 root 5449: REG8(AH) = 0x86;
1.1.1.3 root 5450: m_CF = 1;
1.1 root 5451: #endif
5452: }
5453:
1.1.1.21 root 5454: inline void pcbios_int_15h_8ah()
5455: {
5456: UINT32 size = MAX_MEM - 0x100000;
5457: REG16(AX) = size & 0xffff;
5458: REG16(DX) = size >> 16;
5459: }
5460:
1.1.1.3 root 5461: #if defined(HAS_I386)
1.1 root 5462: inline void pcbios_int_15h_c9h()
5463: {
5464: REG8(AH) = 0x00;
5465: REG8(CH) = cpu_type;
5466: REG8(CL) = cpu_step;
5467: }
1.1.1.3 root 5468: #endif
1.1 root 5469:
5470: inline void pcbios_int_15h_cah()
5471: {
5472: switch(REG8(AL)) {
1.1.1.22 root 5473: case 0x00:
1.1 root 5474: if(REG8(BL) > 0x3f) {
5475: REG8(AH) = 0x03;
1.1.1.3 root 5476: m_CF = 1;
1.1 root 5477: } else if(REG8(BL) < 0x0e) {
5478: REG8(AH) = 0x04;
1.1.1.3 root 5479: m_CF = 1;
1.1 root 5480: } else {
1.1.1.8 root 5481: REG8(CL) = cmos_read(REG8(BL));
1.1 root 5482: }
5483: break;
1.1.1.22 root 5484: case 0x01:
1.1 root 5485: if(REG8(BL) > 0x3f) {
5486: REG8(AH) = 0x03;
1.1.1.3 root 5487: m_CF = 1;
1.1 root 5488: } else if(REG8(BL) < 0x0e) {
5489: REG8(AH) = 0x04;
1.1.1.3 root 5490: m_CF = 1;
1.1 root 5491: } else {
1.1.1.8 root 5492: cmos_write(REG8(BL), REG8(CL));
1.1 root 5493: }
5494: break;
5495: default:
1.1.1.22 root 5496: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 5497: REG8(AH) = 0x86;
1.1.1.3 root 5498: m_CF = 1;
1.1 root 5499: break;
5500: }
5501: }
5502:
1.1.1.22 root 5503: inline void pcbios_int_15h_e8h()
1.1.1.17 root 5504: {
1.1.1.22 root 5505: switch(REG8(AL)) {
5506: #if defined(HAS_I386)
5507: case 0x01:
5508: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
5509: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
5510: break;
1.1.1.17 root 5511: #endif
1.1.1.22 root 5512: default:
5513: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5514: REG8(AH) = 0x86;
5515: m_CF = 1;
5516: break;
5517: }
5518: }
1.1.1.17 root 5519:
1.1.1.16 root 5520: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 5521: {
5522: UINT32 code = 0;
5523:
1.1.1.32! root 5524: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 5525: if(key_buf_char->count() == 0) {
! 5526: if(!update_key_buffer()) {
! 5527: if(clear_buffer) {
! 5528: Sleep(10);
! 5529: } else {
! 5530: maybe_idle();
! 5531: }
1.1.1.14 root 5532: }
5533: }
1.1.1.32! root 5534: if(!clear_buffer) {
! 5535: key_buf_char->store_buffer();
! 5536: key_buf_scan->store_buffer();
! 5537: }
! 5538: if(key_buf_char->count() != 0) {
! 5539: code = key_buf_char->read() | (key_buf_scan->read() << 8);
! 5540: }
! 5541: if(key_buf_char->count() != 0) {
! 5542: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
! 5543: }
! 5544: if(!clear_buffer) {
! 5545: key_buf_char->restore_buffer();
! 5546: key_buf_scan->restore_buffer();
! 5547: }
1.1 root 5548: }
5549: return code;
5550: }
5551:
5552: inline void pcbios_int_16h_00h()
5553: {
1.1.1.14 root 5554: while(key_code == 0 && !m_halted) {
1.1.1.16 root 5555: key_code = pcbios_get_key_code(true);
1.1 root 5556: }
5557: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
5558: if(REG8(AH) == 0x10) {
5559: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
5560: } else {
5561: key_code = ((key_code >> 16) & 0xff00);
5562: }
5563: }
5564: REG16(AX) = key_code & 0xffff;
5565: key_code >>= 16;
5566: }
5567:
5568: inline void pcbios_int_16h_01h()
5569: {
1.1.1.5 root 5570: UINT32 key_code_tmp = key_code;
1.1 root 5571:
1.1.1.5 root 5572: if(key_code_tmp == 0) {
1.1.1.16 root 5573: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 5574: }
1.1.1.14 root 5575: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
5576: if(REG8(AH) == 0x11) {
5577: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
5578: } else {
5579: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 5580: }
5581: }
1.1.1.5 root 5582: if(key_code_tmp != 0) {
5583: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 5584: }
1.1.1.3 root 5585: #if defined(HAS_I386)
1.1.1.5 root 5586: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 5587: #else
1.1.1.5 root 5588: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 5589: #endif
1.1 root 5590: }
5591:
5592: inline void pcbios_int_16h_02h()
5593: {
5594: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
5595: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
5596: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
5597: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
5598: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
5599: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
5600: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
5601: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
5602: }
5603:
5604: inline void pcbios_int_16h_03h()
5605: {
5606: static UINT16 status = 0;
5607:
5608: switch(REG8(AL)) {
5609: case 0x05:
5610: status = REG16(BX);
5611: break;
5612: case 0x06:
5613: REG16(BX) = status;
5614: break;
5615: default:
1.1.1.3 root 5616: m_CF = 1;
1.1 root 5617: break;
5618: }
5619: }
5620:
5621: inline void pcbios_int_16h_05h()
5622: {
1.1.1.32! root 5623: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 5624: key_buf_char->write(REG8(CL));
! 5625: key_buf_scan->write(REG8(CH));
! 5626: }
1.1 root 5627: REG8(AL) = 0x00;
5628: }
5629:
5630: inline void pcbios_int_16h_12h()
5631: {
5632: pcbios_int_16h_02h();
5633:
5634: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
5635: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
5636: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
5637: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
5638: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
5639: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
5640: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
5641: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
5642: }
5643:
5644: inline void pcbios_int_16h_13h()
5645: {
5646: static UINT16 status = 0;
5647:
5648: switch(REG8(AL)) {
5649: case 0x00:
5650: status = REG16(DX);
5651: break;
5652: case 0x01:
5653: REG16(DX) = status;
5654: break;
5655: default:
1.1.1.22 root 5656: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 5657: m_CF = 1;
1.1 root 5658: break;
5659: }
5660: }
5661:
5662: inline void pcbios_int_16h_14h()
5663: {
5664: static UINT8 status = 0;
5665:
5666: switch(REG8(AL)) {
5667: case 0x00:
5668: case 0x01:
5669: status = REG8(AL);
5670: break;
5671: case 0x02:
5672: REG8(AL) = status;
5673: break;
5674: default:
1.1.1.22 root 5675: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 5676: m_CF = 1;
1.1 root 5677: break;
5678: }
5679: }
5680:
1.1.1.24 root 5681: inline void pcbios_int_16h_55h()
5682: {
5683: switch(REG8(AL)) {
5684: case 0x00:
5685: // keyboard tsr is not present
5686: break;
5687: case 0xfe:
5688: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
5689: break;
5690: case 0xff:
5691: break;
5692: default:
5693: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5694: m_CF = 1;
5695: break;
5696: }
5697: }
5698:
1.1.1.30 root 5699: inline void pcbios_int_16h_6fh()
5700: {
5701: switch(REG8(AL)) {
5702: case 0x00:
5703: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
5704: break;
5705: default:
5706: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5707: m_CF = 1;
5708: break;
5709: }
5710: }
5711:
1.1 root 5712: inline void pcbios_int_1ah_00h()
5713: {
1.1.1.19 root 5714: pcbios_update_daily_timer_counter(timeGetTime());
5715: REG16(CX) = *(UINT16 *)(mem + 0x46e);
5716: REG16(DX) = *(UINT16 *)(mem + 0x46c);
5717: REG8(AL) = mem[0x470];
5718: mem[0x470] = 0;
1.1 root 5719: }
5720:
5721: inline int to_bcd(int t)
5722: {
5723: int u = (t % 100) / 10;
5724: return (u << 4) | (t % 10);
5725: }
5726:
5727: inline void pcbios_int_1ah_02h()
5728: {
5729: SYSTEMTIME time;
5730:
5731: GetLocalTime(&time);
5732: REG8(CH) = to_bcd(time.wHour);
5733: REG8(CL) = to_bcd(time.wMinute);
5734: REG8(DH) = to_bcd(time.wSecond);
5735: REG8(DL) = 0x00;
5736: }
5737:
5738: inline void pcbios_int_1ah_04h()
5739: {
5740: SYSTEMTIME time;
5741:
5742: GetLocalTime(&time);
5743: REG8(CH) = to_bcd(time.wYear / 100);
5744: REG8(CL) = to_bcd(time.wYear);
5745: REG8(DH) = to_bcd(time.wMonth);
5746: REG8(DL) = to_bcd(time.wDay);
5747: }
5748:
5749: inline void pcbios_int_1ah_0ah()
5750: {
5751: SYSTEMTIME time;
5752: FILETIME file_time;
5753: WORD dos_date, dos_time;
5754:
5755: GetLocalTime(&time);
5756: SystemTimeToFileTime(&time, &file_time);
5757: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
5758: REG16(CX) = dos_date;
5759: }
5760:
5761: // msdos system call
5762:
5763: inline void msdos_int_21h_00h()
5764: {
1.1.1.3 root 5765: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 5766: }
5767:
5768: inline void msdos_int_21h_01h()
5769: {
5770: REG8(AL) = msdos_getche();
1.1.1.26 root 5771: ctrl_c_detected = ctrl_c_pressed;
5772:
1.1.1.8 root 5773: // some seconds may be passed in console
1.1 root 5774: hardware_update();
5775: }
5776:
5777: inline void msdos_int_21h_02h()
5778: {
5779: msdos_putch(REG8(DL));
1.1.1.26 root 5780: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5781: }
5782:
5783: inline void msdos_int_21h_03h()
5784: {
5785: REG8(AL) = msdos_aux_in();
5786: }
5787:
5788: inline void msdos_int_21h_04h()
5789: {
5790: msdos_aux_out(REG8(DL));
5791: }
5792:
5793: inline void msdos_int_21h_05h()
5794: {
5795: msdos_prn_out(REG8(DL));
5796: }
5797:
5798: inline void msdos_int_21h_06h()
5799: {
5800: if(REG8(DL) == 0xff) {
5801: if(msdos_kbhit()) {
5802: REG8(AL) = msdos_getch();
1.1.1.3 root 5803: #if defined(HAS_I386)
5804: m_ZF = 0;
5805: #else
5806: m_ZeroVal = 1;
5807: #endif
1.1 root 5808: } else {
5809: REG8(AL) = 0;
1.1.1.3 root 5810: #if defined(HAS_I386)
5811: m_ZF = 1;
5812: #else
5813: m_ZeroVal = 0;
5814: #endif
1.1.1.14 root 5815: maybe_idle();
1.1 root 5816: }
5817: } else {
5818: msdos_putch(REG8(DL));
5819: }
5820: }
5821:
5822: inline void msdos_int_21h_07h()
5823: {
5824: REG8(AL) = msdos_getch();
1.1.1.26 root 5825:
1.1.1.8 root 5826: // some seconds may be passed in console
1.1 root 5827: hardware_update();
5828: }
5829:
5830: inline void msdos_int_21h_08h()
5831: {
5832: REG8(AL) = msdos_getch();
1.1.1.26 root 5833: ctrl_c_detected = ctrl_c_pressed;
5834:
1.1.1.8 root 5835: // some seconds may be passed in console
1.1 root 5836: hardware_update();
5837: }
5838:
5839: inline void msdos_int_21h_09h()
5840: {
1.1.1.21 root 5841: msdos_stdio_reopen();
5842:
1.1.1.20 root 5843: process_t *process = msdos_process_info_get(current_psp);
5844: int fd = msdos_psp_get_file_table(1, current_psp);
5845:
1.1.1.14 root 5846: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
5847: int len = 0;
1.1 root 5848:
1.1.1.14 root 5849: while(str[len] != '$' && len < 0x10000) {
5850: len++;
5851: }
1.1.1.20 root 5852: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 5853: // stdout is redirected to file
1.1.1.20 root 5854: msdos_write(fd, str, len);
1.1 root 5855: } else {
5856: for(int i = 0; i < len; i++) {
1.1.1.14 root 5857: msdos_putch(str[i]);
1.1 root 5858: }
5859: }
1.1.1.26 root 5860: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5861: }
5862:
5863: inline void msdos_int_21h_0ah()
5864: {
1.1.1.3 root 5865: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 5866: int max = mem[ofs] - 1;
5867: UINT8 *buf = mem + ofs + 2;
5868: int chr, p = 0;
5869:
5870: while((chr = msdos_getch()) != 0x0d) {
1.1.1.26 root 5871: if(ctrl_c_pressed) {
5872: p = 0;
5873: msdos_putch(chr);
5874: break;
5875: } else if(chr == 0x00) {
1.1 root 5876: // skip 2nd byte
5877: msdos_getch();
5878: } else if(chr == 0x08) {
5879: // back space
5880: if(p > 0) {
5881: p--;
1.1.1.20 root 5882: if(msdos_ctrl_code_check(buf[p])) {
5883: msdos_putch(chr);
5884: msdos_putch(chr);
5885: msdos_putch(' ');
5886: msdos_putch(' ');
5887: msdos_putch(chr);
5888: msdos_putch(chr);
5889: } else {
5890: msdos_putch(chr);
5891: msdos_putch(' ');
5892: msdos_putch(chr);
5893: }
1.1 root 5894: }
5895: } else if(p < max) {
5896: buf[p++] = chr;
5897: msdos_putch(chr);
5898: }
5899: }
5900: buf[p] = 0x0d;
5901: mem[ofs + 1] = p;
1.1.1.26 root 5902: ctrl_c_detected = ctrl_c_pressed;
5903:
1.1.1.8 root 5904: // some seconds may be passed in console
1.1 root 5905: hardware_update();
5906: }
5907:
5908: inline void msdos_int_21h_0bh()
5909: {
5910: if(msdos_kbhit()) {
5911: REG8(AL) = 0xff;
5912: } else {
5913: REG8(AL) = 0x00;
1.1.1.14 root 5914: maybe_idle();
1.1 root 5915: }
1.1.1.26 root 5916: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5917: }
5918:
5919: inline void msdos_int_21h_0ch()
5920: {
5921: // clear key buffer
1.1.1.21 root 5922: msdos_stdio_reopen();
5923:
1.1.1.20 root 5924: process_t *process = msdos_process_info_get(current_psp);
5925: int fd = msdos_psp_get_file_table(0, current_psp);
5926:
5927: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 5928: // stdin is redirected to file
5929: } else {
5930: while(msdos_kbhit()) {
5931: msdos_getch();
5932: }
5933: }
5934:
5935: switch(REG8(AL)) {
5936: case 0x01:
5937: msdos_int_21h_01h();
5938: break;
5939: case 0x06:
5940: msdos_int_21h_06h();
5941: break;
5942: case 0x07:
5943: msdos_int_21h_07h();
5944: break;
5945: case 0x08:
5946: msdos_int_21h_08h();
5947: break;
5948: case 0x0a:
5949: msdos_int_21h_0ah();
5950: break;
5951: default:
1.1.1.22 root 5952: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
5953: // REG16(AX) = 0x01;
5954: // m_CF = 1;
1.1 root 5955: break;
5956: }
5957: }
5958:
5959: inline void msdos_int_21h_0dh()
5960: {
5961: }
5962:
5963: inline void msdos_int_21h_0eh()
5964: {
5965: if(REG8(DL) < 26) {
5966: _chdrive(REG8(DL) + 1);
5967: msdos_cds_update(REG8(DL));
1.1.1.23 root 5968: msdos_sda_update(current_psp);
1.1 root 5969: }
5970: REG8(AL) = 26; // zdrive
5971: }
5972:
1.1.1.14 root 5973: inline void msdos_int_21h_0fh()
5974: {
5975: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5976: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5977: char *path = msdos_fcb_path(fcb);
5978: 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 5979:
1.1.1.14 root 5980: if(hFile == INVALID_HANDLE_VALUE) {
5981: REG8(AL) = 0xff;
5982: } else {
5983: REG8(AL) = 0;
5984: fcb->current_block = 0;
5985: fcb->record_size = 128;
5986: fcb->file_size = GetFileSize(hFile, NULL);
5987: fcb->handle = hFile;
5988: fcb->cur_record = 0;
5989: }
5990: }
5991:
5992: inline void msdos_int_21h_10h()
5993: {
5994: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5995: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5996:
5997: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
5998: }
5999:
1.1 root 6000: inline void msdos_int_21h_11h()
6001: {
1.1.1.3 root 6002: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6003: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 6004:
6005: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6006: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6007: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
6008: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 6009: char *path = msdos_fcb_path(fcb);
6010: WIN32_FIND_DATA fd;
6011:
1.1.1.13 root 6012: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
6013: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6014: FindClose(dtainfo->find_handle);
6015: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6016: }
6017: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6018: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
6019: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6020:
1.1.1.14 root 6021: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6022: dtainfo->allowable_mask &= ~8;
1.1 root 6023: }
1.1.1.14 root 6024: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6025: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6026: !msdos_find_file_has_8dot3name(&fd)) {
6027: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6028: FindClose(dtainfo->find_handle);
6029: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6030: break;
6031: }
6032: }
6033: }
1.1.1.13 root 6034: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6035: if(ext_fcb->flag == 0xff) {
6036: ext_find->flag = 0xff;
6037: memset(ext_find->reserved, 0, 5);
6038: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
6039: }
6040: find->drive = _getdrive();
1.1.1.13 root 6041: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 6042: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
6043: find->nt_res = 0;
6044: msdos_find_file_conv_local_time(&fd);
6045: find->create_time_ms = 0;
6046: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
6047: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
6048: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
6049: find->cluster_hi = find->cluster_lo = 0;
6050: find->file_size = fd.nFileSizeLow;
6051: REG8(AL) = 0x00;
1.1.1.14 root 6052: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6053: if(ext_fcb->flag == 0xff) {
6054: ext_find->flag = 0xff;
6055: memset(ext_find->reserved, 0, 5);
6056: ext_find->attribute = 8;
6057: }
6058: find->drive = _getdrive();
6059: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
6060: find->attribute = 8;
6061: find->nt_res = 0;
6062: msdos_find_file_conv_local_time(&fd);
6063: find->create_time_ms = 0;
6064: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
6065: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
6066: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
6067: find->cluster_hi = find->cluster_lo = 0;
6068: find->file_size = 0;
1.1.1.14 root 6069: dtainfo->allowable_mask &= ~8;
1.1 root 6070: REG8(AL) = 0x00;
6071: } else {
6072: REG8(AL) = 0xff;
6073: }
6074: }
6075:
6076: inline void msdos_int_21h_12h()
6077: {
1.1.1.3 root 6078: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 6079: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 6080:
6081: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6082: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6083: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
6084: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 6085: WIN32_FIND_DATA fd;
6086:
1.1.1.13 root 6087: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
6088: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6089: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6090: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6091: !msdos_find_file_has_8dot3name(&fd)) {
6092: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6093: FindClose(dtainfo->find_handle);
6094: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6095: break;
6096: }
6097: }
6098: } else {
1.1.1.13 root 6099: FindClose(dtainfo->find_handle);
6100: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6101: }
6102: }
1.1.1.13 root 6103: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6104: if(ext_fcb->flag == 0xff) {
6105: ext_find->flag = 0xff;
6106: memset(ext_find->reserved, 0, 5);
6107: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
6108: }
6109: find->drive = _getdrive();
1.1.1.13 root 6110: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 6111: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
6112: find->nt_res = 0;
6113: msdos_find_file_conv_local_time(&fd);
6114: find->create_time_ms = 0;
6115: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
6116: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
6117: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
6118: find->cluster_hi = find->cluster_lo = 0;
6119: find->file_size = fd.nFileSizeLow;
6120: REG8(AL) = 0x00;
1.1.1.14 root 6121: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6122: if(ext_fcb->flag == 0xff) {
6123: ext_find->flag = 0xff;
6124: memset(ext_find->reserved, 0, 5);
6125: ext_find->attribute = 8;
6126: }
6127: find->drive = _getdrive();
6128: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
6129: find->attribute = 8;
6130: find->nt_res = 0;
6131: msdos_find_file_conv_local_time(&fd);
6132: find->create_time_ms = 0;
6133: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
6134: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
6135: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
6136: find->cluster_hi = find->cluster_lo = 0;
6137: find->file_size = 0;
1.1.1.14 root 6138: dtainfo->allowable_mask &= ~8;
1.1 root 6139: REG8(AL) = 0x00;
6140: } else {
6141: REG8(AL) = 0xff;
6142: }
6143: }
6144:
6145: inline void msdos_int_21h_13h()
6146: {
1.1.1.3 root 6147: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 6148: REG8(AL) = 0xff;
6149: } else {
6150: REG8(AL) = 0x00;
6151: }
6152: }
6153:
1.1.1.16 root 6154: inline void msdos_int_21h_14h()
6155: {
6156: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6157: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6158: process_t *process = msdos_process_info_get(current_psp);
6159: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6160: DWORD num = 0;
6161:
6162: memset(mem + dta_laddr, 0, fcb->record_size);
6163: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
6164: REG8(AL) = 1;
6165: } else {
6166: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
6167: fcb->current_block = (position & 0xffffff) / fcb->record_size;
6168: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
6169: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
6170: }
6171: }
6172:
6173: inline void msdos_int_21h_15h()
1.1.1.14 root 6174: {
6175: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6176: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 6177: process_t *process = msdos_process_info_get(current_psp);
6178: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6179: DWORD num = 0;
1.1.1.14 root 6180:
1.1.1.16 root 6181: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
6182: REG8(AL) = 1;
6183: } else {
6184: fcb->file_size = GetFileSize(fcb->handle, NULL);
6185: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
6186: fcb->current_block = (position & 0xffffff) / fcb->record_size;
6187: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
6188: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
6189: }
6190: }
6191:
6192: inline void msdos_int_21h_16h()
6193: {
6194: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6195: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 6196: char *path = msdos_fcb_path(fcb);
6197: 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 6198:
1.1.1.14 root 6199: if(hFile == INVALID_HANDLE_VALUE) {
6200: REG8(AL) = 0xff;
6201: } else {
6202: REG8(AL) = 0;
6203: fcb->current_block = 0;
6204: fcb->record_size = 128;
6205: fcb->file_size = 0;
6206: fcb->handle = hFile;
6207: fcb->cur_record = 0;
6208: }
6209: }
6210:
1.1.1.16 root 6211: inline void msdos_int_21h_17h()
6212: {
6213: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6214: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
6215: char *path_src = msdos_fcb_path(fcb_src);
6216: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
6217: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
6218: char *path_dst = msdos_fcb_path(fcb_dst);
6219:
6220: if(rename(path_src, path_dst)) {
6221: REG8(AL) = 0xff;
6222: } else {
6223: REG8(AL) = 0;
6224: }
6225: }
6226:
1.1 root 6227: inline void msdos_int_21h_18h()
6228: {
6229: REG8(AL) = 0x00;
6230: }
6231:
6232: inline void msdos_int_21h_19h()
6233: {
6234: REG8(AL) = _getdrive() - 1;
6235: }
6236:
6237: inline void msdos_int_21h_1ah()
6238: {
6239: process_t *process = msdos_process_info_get(current_psp);
6240:
6241: process->dta.w.l = REG16(DX);
1.1.1.3 root 6242: process->dta.w.h = SREG(DS);
1.1.1.23 root 6243: msdos_sda_update(current_psp);
1.1 root 6244: }
6245:
6246: inline void msdos_int_21h_1bh()
6247: {
6248: int drive_num = _getdrive() - 1;
6249: UINT16 seg, ofs;
6250:
6251: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6252: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6253: REG8(AL) = dpb->highest_sector_num + 1;
6254: REG16(CX) = dpb->bytes_per_sector;
6255: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 6256: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 6257: } else {
6258: REG8(AL) = 0xff;
1.1.1.3 root 6259: m_CF = 1;
1.1 root 6260: }
6261:
6262: }
6263:
6264: inline void msdos_int_21h_1ch()
6265: {
6266: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
6267: UINT16 seg, ofs;
6268:
6269: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6270: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6271: REG8(AL) = dpb->highest_sector_num + 1;
6272: REG16(CX) = dpb->bytes_per_sector;
6273: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 6274: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 6275: } else {
6276: REG8(AL) = 0xff;
1.1.1.3 root 6277: m_CF = 1;
1.1 root 6278: }
6279:
6280: }
6281:
6282: inline void msdos_int_21h_1dh()
6283: {
6284: REG8(AL) = 0;
6285: }
6286:
6287: inline void msdos_int_21h_1eh()
6288: {
6289: REG8(AL) = 0;
6290: }
6291:
6292: inline void msdos_int_21h_1fh()
6293: {
6294: int drive_num = _getdrive() - 1;
6295: UINT16 seg, ofs;
6296:
6297: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6298: REG8(AL) = 0;
1.1.1.3 root 6299: SREG(DS) = seg;
6300: i386_load_segment_descriptor(DS);
1.1 root 6301: REG16(BX) = ofs;
6302: } else {
6303: REG8(AL) = 0xff;
1.1.1.3 root 6304: m_CF = 1;
1.1 root 6305: }
6306: }
6307:
6308: inline void msdos_int_21h_20h()
6309: {
6310: REG8(AL) = 0;
6311: }
6312:
1.1.1.14 root 6313: inline void msdos_int_21h_21h()
6314: {
6315: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6316: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6317:
6318: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6319: REG8(AL) = 1;
6320: } else {
6321: process_t *process = msdos_process_info_get(current_psp);
6322: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6323: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 6324: DWORD num = 0;
1.1.1.14 root 6325: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
6326: REG8(AL) = 1;
6327: } else {
6328: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6329: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 6330: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 6331: }
6332: }
6333: }
6334:
6335: inline void msdos_int_21h_22h()
6336: {
6337: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6338: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6339:
6340: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6341: REG8(AL) = 0xff;
6342: } else {
6343: process_t *process = msdos_process_info_get(current_psp);
6344: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 6345: DWORD num = 0;
1.1.1.14 root 6346: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
6347: fcb->file_size = GetFileSize(fcb->handle, NULL);
6348: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6349: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 6350: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 6351: }
6352: }
6353:
1.1.1.16 root 6354: inline void msdos_int_21h_23h()
6355: {
6356: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6357: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6358: char *path = msdos_fcb_path(fcb);
6359: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6360:
6361: if(hFile == INVALID_HANDLE_VALUE) {
6362: REG8(AL) = 0xff;
6363: } else {
6364: UINT32 size = GetFileSize(hFile, NULL);
6365: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
6366: REG8(AL) = 0;
6367: }
6368: }
6369:
6370: inline void msdos_int_21h_24h()
6371: {
6372: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6373: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6374:
6375: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
6376: }
6377:
1.1 root 6378: inline void msdos_int_21h_25h()
6379: {
6380: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 6381: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 6382: }
6383:
6384: inline void msdos_int_21h_26h()
6385: {
6386: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
6387:
6388: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
6389: psp->first_mcb = REG16(DX) + 16;
6390: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6391: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6392: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6393: psp->parent_psp = 0;
6394: }
6395:
1.1.1.16 root 6396: inline void msdos_int_21h_27h()
6397: {
6398: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6399: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6400:
6401: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6402: REG8(AL) = 1;
6403: } else {
6404: process_t *process = msdos_process_info_get(current_psp);
6405: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6406: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
6407: DWORD num = 0;
6408: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
6409: REG8(AL) = 1;
6410: } else {
6411: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6412: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
6413: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
6414: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
6415: }
6416: }
6417: }
6418:
6419: inline void msdos_int_21h_28h()
6420: {
6421: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6422: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6423:
6424: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6425: REG8(AL) = 0xff;
6426: } else {
6427: process_t *process = msdos_process_info_get(current_psp);
6428: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6429: DWORD num = 0;
6430: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
6431: fcb->file_size = GetFileSize(fcb->handle, NULL);
6432: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6433: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
6434: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
6435: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
6436: }
6437: }
6438:
1.1 root 6439: inline void msdos_int_21h_29h()
6440: {
1.1.1.20 root 6441: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
6442: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 6443: UINT8 drv = 0;
6444: char sep_chars[] = ":.;,=+";
6445: char end_chars[] = "\\<>|/\"[]";
6446: char spc_chars[] = " \t";
6447:
1.1.1.20 root 6448: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
6449: buffer[1023] = 0;
6450: memset(name, 0x20, sizeof(name));
6451: memset(ext, 0x20, sizeof(ext));
6452:
1.1 root 6453: if(REG8(AL) & 1) {
1.1.1.20 root 6454: ofs += strspn((char *)(buffer + ofs), spc_chars);
6455: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 6456: ofs++;
6457: }
6458: }
1.1.1.20 root 6459: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 6460:
1.1.1.24 root 6461: if(buffer[ofs + 1] == ':') {
6462: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
6463: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 6464: ofs += 2;
1.1.1.24 root 6465: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
6466: ofs++;
6467: }
6468: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
6469: drv = buffer[ofs] - 'A' + 1;
1.1 root 6470: ofs += 2;
1.1.1.24 root 6471: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
6472: ofs++;
6473: }
1.1 root 6474: }
6475: }
1.1.1.20 root 6476: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
6477: UINT8 c = buffer[ofs];
6478: if(is_kanji) {
6479: is_kanji = 0;
6480: } else if(msdos_lead_byte_check(c)) {
6481: is_kanji = 1;
6482: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 6483: break;
6484: } else if(c >= 'a' && c <= 'z') {
6485: c -= 0x20;
6486: }
6487: ofs++;
6488: name[i] = c;
6489: }
1.1.1.20 root 6490: if(buffer[ofs] == '.') {
1.1 root 6491: ofs++;
1.1.1.20 root 6492: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
6493: UINT8 c = buffer[ofs];
6494: if(is_kanji) {
6495: is_kanji = 0;
6496: } else if(msdos_lead_byte_check(c)) {
6497: is_kanji = 1;
6498: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 6499: break;
6500: } else if(c >= 'a' && c <= 'z') {
6501: c -= 0x20;
6502: }
6503: ofs++;
6504: ext[i] = c;
6505: }
6506: }
1.1.1.20 root 6507: int si = REG16(SI) + ofs;
1.1.1.3 root 6508: int ds = SREG(DS);
1.1 root 6509: while(si > 0xffff) {
6510: si -= 0x10;
6511: ds++;
6512: }
6513: REG16(SI) = si;
1.1.1.3 root 6514: SREG(DS) = ds;
6515: i386_load_segment_descriptor(DS);
1.1 root 6516:
1.1.1.3 root 6517: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 6518: if(!(REG8(AL) & 2) || drv != 0) {
6519: fcb[0] = drv;
6520: }
6521: if(!(REG8(AL) & 4) || name[0] != 0x20) {
6522: memcpy(fcb + 1, name, 8);
6523: }
6524: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
6525: memcpy(fcb + 9, ext, 3);
6526: }
6527: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 6528: if(fcb[i] == '*') {
6529: found_star = 1;
6530: }
6531: if(found_star) {
6532: fcb[i] = '?';
6533: }
6534: }
1.1.1.20 root 6535: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 6536: if(fcb[i] == '*') {
6537: found_star = 1;
6538: }
6539: if(found_star) {
6540: fcb[i] = '?';
6541: }
6542: }
6543:
6544: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
6545: if(memchr(fcb + 1, '?', 8 + 3)) {
6546: REG8(AL) = 0x01;
1.1.1.20 root 6547: } else {
6548: REG8(AL) = 0x00;
1.1 root 6549: }
6550: } else {
6551: REG8(AL) = 0xff;
6552: }
6553: }
6554:
6555: inline void msdos_int_21h_2ah()
6556: {
6557: SYSTEMTIME sTime;
6558:
6559: GetLocalTime(&sTime);
6560: REG16(CX) = sTime.wYear;
6561: REG8(DH) = (UINT8)sTime.wMonth;
6562: REG8(DL) = (UINT8)sTime.wDay;
6563: REG8(AL) = (UINT8)sTime.wDayOfWeek;
6564: }
6565:
6566: inline void msdos_int_21h_2bh()
6567: {
1.1.1.14 root 6568: REG8(AL) = 0xff;
1.1 root 6569: }
6570:
6571: inline void msdos_int_21h_2ch()
6572: {
6573: SYSTEMTIME sTime;
6574:
6575: GetLocalTime(&sTime);
6576: REG8(CH) = (UINT8)sTime.wHour;
6577: REG8(CL) = (UINT8)sTime.wMinute;
6578: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 6579: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 6580: }
6581:
6582: inline void msdos_int_21h_2dh()
6583: {
6584: REG8(AL) = 0x00;
6585: }
6586:
6587: inline void msdos_int_21h_2eh()
6588: {
6589: process_t *process = msdos_process_info_get(current_psp);
6590:
6591: process->verify = REG8(AL);
6592: }
6593:
6594: inline void msdos_int_21h_2fh()
6595: {
6596: process_t *process = msdos_process_info_get(current_psp);
6597:
6598: REG16(BX) = process->dta.w.l;
1.1.1.3 root 6599: SREG(ES) = process->dta.w.h;
6600: i386_load_segment_descriptor(ES);
1.1 root 6601: }
6602:
6603: inline void msdos_int_21h_30h()
6604: {
6605: // Version Flag / OEM
1.1.1.27 root 6606: if(REG8(AL) == 0x01) {
1.1.1.29 root 6607: #ifdef SUPPORT_HMA
6608: REG16(BX) = 0x0000;
6609: #else
6610: REG16(BX) = 0x1000; // DOS is in HMA
6611: #endif
1.1 root 6612: } else {
1.1.1.27 root 6613: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
6614: // but this is not correct on Windows 98 SE
6615: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
6616: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 6617: }
1.1.1.27 root 6618: REG16(CX) = 0x0000;
1.1.1.30 root 6619: REG8(AL) = dos_major_version; // 7
6620: REG8(AH) = dos_minor_version; // 10
1.1 root 6621: }
6622:
6623: inline void msdos_int_21h_31h()
6624: {
1.1.1.29 root 6625: try {
6626: msdos_mem_realloc(current_psp, REG16(DX), NULL);
6627: } catch(...) {
6628: // recover the broken mcb
6629: int mcb_seg = current_psp - 1;
6630: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6631: if(mcb_seg < (MEMORY_END >> 4)) {
6632: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
6633: mcb->mz = 'M';
6634: } else {
6635: mcb->mz = 'Z';
6636: }
1.1.1.30 root 6637: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
1.1.1.29 root 6638: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
6639: } else {
6640: mcb->mz = 'Z';
1.1.1.30 root 6641: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 6642: }
6643: msdos_mem_realloc(current_psp, REG16(DX), NULL);
6644: }
1.1 root 6645: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
6646: }
6647:
6648: inline void msdos_int_21h_32h()
6649: {
6650: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
6651: UINT16 seg, ofs;
6652:
6653: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6654: REG8(AL) = 0;
1.1.1.3 root 6655: SREG(DS) = seg;
6656: i386_load_segment_descriptor(DS);
1.1 root 6657: REG16(BX) = ofs;
6658: } else {
6659: REG8(AL) = 0xff;
1.1.1.3 root 6660: m_CF = 1;
1.1 root 6661: }
6662: }
6663:
6664: inline void msdos_int_21h_33h()
6665: {
6666: char path[MAX_PATH];
6667:
6668: switch(REG8(AL)) {
6669: case 0x00:
1.1.1.26 root 6670: REG8(DL) = ctrl_c_checking;
1.1 root 6671: break;
6672: case 0x01:
1.1.1.26 root 6673: ctrl_c_checking = REG8(DL);
1.1 root 6674: break;
6675: case 0x05:
6676: GetSystemDirectory(path, MAX_PATH);
6677: if(path[0] >= 'a' && path[0] <= 'z') {
6678: REG8(DL) = path[0] - 'a' + 1;
6679: } else {
6680: REG8(DL) = path[0] - 'A' + 1;
6681: }
6682: break;
6683: case 0x06:
1.1.1.2 root 6684: // MS-DOS version (7.10)
1.1 root 6685: REG8(BL) = 7;
1.1.1.2 root 6686: REG8(BH) = 10;
1.1 root 6687: REG8(DL) = 0;
1.1.1.29 root 6688: #ifdef SUPPORT_HMA
6689: REG8(DH) = 0x00;
6690: #else
6691: REG8(DH) = 0x10; // DOS is in HMA
6692: #endif
1.1 root 6693: break;
1.1.1.6 root 6694: case 0x07:
6695: if(REG8(DL) == 0) {
6696: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
6697: } else if(REG8(DL) == 1) {
6698: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
6699: }
6700: break;
1.1 root 6701: default:
1.1.1.22 root 6702: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 6703: REG16(AX) = 0x01;
1.1.1.3 root 6704: m_CF = 1;
1.1 root 6705: break;
6706: }
6707: }
6708:
1.1.1.23 root 6709: inline void msdos_int_21h_34h()
6710: {
6711: SREG(ES) = SDA_TOP >> 4;
6712: i386_load_segment_descriptor(ES);
6713: REG16(BX) = offsetof(sda_t, indos_flag);;
6714: }
6715:
1.1 root 6716: inline void msdos_int_21h_35h()
6717: {
6718: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 6719: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
6720: i386_load_segment_descriptor(ES);
1.1 root 6721: }
6722:
6723: inline void msdos_int_21h_36h()
6724: {
6725: struct _diskfree_t df = {0};
6726:
6727: if(_getdiskfree(REG8(DL), &df) == 0) {
6728: REG16(AX) = (UINT16)df.sectors_per_cluster;
6729: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 6730: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
6731: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 6732: } else {
6733: REG16(AX) = 0xffff;
6734: }
6735: }
6736:
6737: inline void msdos_int_21h_37h()
6738: {
1.1.1.22 root 6739: static UINT8 dev_flag = 0xff;
1.1 root 6740:
6741: switch(REG8(AL)) {
6742: case 0x00:
1.1.1.22 root 6743: {
6744: process_t *process = msdos_process_info_get(current_psp);
6745: REG8(AL) = 0x00;
6746: REG8(DL) = process->switchar;
6747: }
1.1 root 6748: break;
6749: case 0x01:
1.1.1.22 root 6750: {
6751: process_t *process = msdos_process_info_get(current_psp);
6752: REG8(AL) = 0x00;
6753: process->switchar = REG8(DL);
1.1.1.23 root 6754: msdos_sda_update(current_psp);
1.1.1.22 root 6755: }
6756: break;
6757: case 0x02:
6758: REG8(DL) = dev_flag;
6759: break;
6760: case 0x03:
6761: dev_flag = REG8(DL);
6762: break;
6763: case 0xd0:
6764: case 0xd1:
6765: case 0xd2:
6766: case 0xd3:
6767: case 0xd4:
6768: case 0xd5:
6769: case 0xd6:
6770: case 0xd7:
6771: case 0xdc:
6772: case 0xdd:
6773: case 0xde:
6774: case 0xdf:
6775: // diet ???
6776: REG16(AX) = 1;
1.1 root 6777: break;
6778: default:
1.1.1.22 root 6779: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 6780: REG16(AX) = 1;
6781: break;
6782: }
6783: }
6784:
1.1.1.19 root 6785: int get_country_info(country_info_t *ci)
1.1.1.17 root 6786: {
6787: char LCdata[80];
6788:
1.1.1.19 root 6789: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 6790: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
6791: ci->currency_dec_digits = atoi(LCdata);
6792: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
6793: ci->currency_format = *LCdata - '0';
6794: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
6795: ci->date_format = *LCdata - '0';
6796: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
6797: memcpy(&ci->currency_symbol, LCdata, 4);
6798: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
6799: *ci->date_sep = *LCdata;
6800: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
6801: *ci->dec_sep = *LCdata;
6802: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
6803: *ci->list_sep = *LCdata;
6804: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
6805: *ci->thou_sep = *LCdata;
6806: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
6807: *ci->time_sep = *LCdata;
6808: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
6809: if(strchr(LCdata, 'H') != NULL) {
6810: ci->time_format = 1;
6811: }
1.1.1.27 root 6812: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 6813: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 6814: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
6815: return atoi(LCdata);
6816: }
6817:
1.1.1.14 root 6818: inline void msdos_int_21h_38h()
6819: {
6820: switch(REG8(AL)) {
6821: case 0x00:
1.1.1.19 root 6822: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 6823: break;
6824: default:
1.1.1.22 root 6825: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 6826: REG16(AX) = 2;
6827: m_CF = 1;
6828: break;
6829: }
6830: }
6831:
1.1 root 6832: inline void msdos_int_21h_39h(int lfn)
6833: {
1.1.1.3 root 6834: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6835: REG16(AX) = errno;
1.1.1.3 root 6836: m_CF = 1;
1.1 root 6837: }
6838: }
6839:
6840: inline void msdos_int_21h_3ah(int lfn)
6841: {
1.1.1.3 root 6842: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6843: REG16(AX) = errno;
1.1.1.3 root 6844: m_CF = 1;
1.1 root 6845: }
6846: }
6847:
6848: inline void msdos_int_21h_3bh(int lfn)
6849: {
1.1.1.3 root 6850: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 6851: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 6852: m_CF = 1;
1.1 root 6853: }
6854: }
6855:
6856: inline void msdos_int_21h_3ch()
6857: {
1.1.1.3 root 6858: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6859: int attr = GetFileAttributes(path);
1.1.1.29 root 6860: int fd = -1, c;
1.1.1.11 root 6861: UINT16 info;
1.1 root 6862:
1.1.1.11 root 6863: if(msdos_is_con_path(path)) {
6864: fd = _open("CON", _O_WRONLY | _O_BINARY);
6865: info = 0x80d3;
1.1.1.29 root 6866: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
6867: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), _O_WRONLY | _O_BINARY)) == -1) {
6868: fd = _open("NUL", _O_WRONLY | _O_BINARY);
6869: }
1.1.1.14 root 6870: info = 0x80d3;
1.1.1.29 root 6871: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 6872: fd = _open("NUL", _O_WRONLY | _O_BINARY);
6873: info = 0x80d3;
1.1 root 6874: } else {
6875: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 6876: info = msdos_drive_number(path);
1.1 root 6877: }
6878: if(fd != -1) {
6879: if(attr == -1) {
6880: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
6881: }
6882: SetFileAttributes(path, attr);
6883: REG16(AX) = fd;
1.1.1.11 root 6884: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 6885: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6886: } else {
6887: REG16(AX) = errno;
1.1.1.3 root 6888: m_CF = 1;
1.1 root 6889: }
6890: }
6891:
6892: inline void msdos_int_21h_3dh()
6893: {
1.1.1.3 root 6894: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6895: int mode = REG8(AL) & 0x03;
1.1.1.29 root 6896: int fd = -1, c;
1.1.1.11 root 6897: UINT16 info;
1.1 root 6898:
6899: if(mode < 0x03) {
1.1.1.11 root 6900: if(msdos_is_con_path(path)) {
1.1.1.13 root 6901: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 6902: info = 0x80d3;
1.1.1.29 root 6903: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
6904: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
6905: fd = msdos_open("NUL", file_mode[mode].mode);
6906: }
1.1.1.14 root 6907: info = 0x80d3;
1.1.1.29 root 6908: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 6909: fd = msdos_open("NUL", file_mode[mode].mode);
6910: info = 0x80d3;
1.1.1.11 root 6911: } else {
1.1.1.13 root 6912: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 6913: info = msdos_drive_number(path);
6914: }
1.1 root 6915: if(fd != -1) {
6916: REG16(AX) = fd;
1.1.1.11 root 6917: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 6918: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6919: } else {
6920: REG16(AX) = errno;
1.1.1.3 root 6921: m_CF = 1;
1.1 root 6922: }
6923: } else {
6924: REG16(AX) = 0x0c;
1.1.1.3 root 6925: m_CF = 1;
1.1 root 6926: }
6927: }
6928:
6929: inline void msdos_int_21h_3eh()
6930: {
6931: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6932: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6933:
1.1.1.20 root 6934: if(fd < process->max_files && file_handler[fd].valid) {
6935: _close(fd);
6936: msdos_file_handler_close(fd);
6937: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 6938: } else {
6939: REG16(AX) = 0x06;
1.1.1.3 root 6940: m_CF = 1;
1.1 root 6941: }
6942: }
6943:
6944: inline void msdos_int_21h_3fh()
6945: {
6946: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6947: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6948:
1.1.1.20 root 6949: if(fd < process->max_files && file_handler[fd].valid) {
6950: if(file_mode[file_handler[fd].mode].in) {
6951: if(file_handler[fd].atty) {
1.1 root 6952: // BX is stdin or is redirected to stdin
1.1.1.3 root 6953: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 6954: int max = REG16(CX);
6955: int p = 0;
6956:
6957: while(max > p) {
6958: int chr = msdos_getch();
6959:
1.1.1.26 root 6960: if(ctrl_c_pressed) {
6961: p = 0;
6962: buf[p++] = 0x0d;
6963: if(max > p) {
6964: buf[p++] = 0x0a;
6965: }
6966: msdos_putch(chr);
6967: msdos_putch('\n');
6968: break;
6969: } else if(chr == 0x00) {
1.1 root 6970: // skip 2nd byte
6971: msdos_getch();
6972: } else if(chr == 0x0d) {
6973: // carriage return
6974: buf[p++] = 0x0d;
6975: if(max > p) {
6976: buf[p++] = 0x0a;
6977: }
1.1.1.14 root 6978: msdos_putch('\n');
1.1 root 6979: break;
6980: } else if(chr == 0x08) {
6981: // back space
6982: if(p > 0) {
6983: p--;
1.1.1.20 root 6984: if(msdos_ctrl_code_check(buf[p])) {
6985: msdos_putch(chr);
6986: msdos_putch(chr);
6987: msdos_putch(' ');
6988: msdos_putch(' ');
6989: msdos_putch(chr);
6990: msdos_putch(chr);
6991: } else {
6992: msdos_putch(chr);
6993: msdos_putch(' ');
6994: msdos_putch(chr);
6995: }
1.1 root 6996: }
6997: } else {
6998: buf[p++] = chr;
6999: msdos_putch(chr);
7000: }
7001: }
7002: REG16(AX) = p;
1.1.1.26 root 7003:
1.1.1.8 root 7004: // some seconds may be passed in console
1.1 root 7005: hardware_update();
7006: } else {
1.1.1.20 root 7007: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 7008: }
7009: } else {
7010: REG16(AX) = 0x05;
1.1.1.3 root 7011: m_CF = 1;
1.1 root 7012: }
7013: } else {
7014: REG16(AX) = 0x06;
1.1.1.3 root 7015: m_CF = 1;
1.1 root 7016: }
7017: }
7018:
7019: inline void msdos_int_21h_40h()
7020: {
7021: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7022: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7023:
1.1.1.20 root 7024: if(fd < process->max_files && file_handler[fd].valid) {
7025: if(file_mode[file_handler[fd].mode].out) {
1.1 root 7026: if(REG16(CX)) {
1.1.1.20 root 7027: if(file_handler[fd].atty) {
1.1 root 7028: // BX is stdout/stderr or is redirected to stdout
7029: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 7030: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 7031: }
7032: REG16(AX) = REG16(CX);
7033: } else {
1.1.1.20 root 7034: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 7035: }
7036: } else {
1.1.1.20 root 7037: UINT32 pos = _tell(fd);
7038: _lseek(fd, 0, SEEK_END);
7039: UINT32 size = _tell(fd);
1.1.1.12 root 7040: if(pos < size) {
1.1.1.20 root 7041: _lseek(fd, pos, SEEK_SET);
7042: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 7043: } else {
7044: for(UINT32 i = size; i < pos; i++) {
7045: UINT8 tmp = 0;
1.1.1.23 root 7046: msdos_write(fd, &tmp, 1);
1.1.1.12 root 7047: }
1.1.1.20 root 7048: _lseek(fd, pos, SEEK_SET);
1.1 root 7049: }
1.1.1.23 root 7050: REG16(AX) = 0;
1.1 root 7051: }
7052: } else {
7053: REG16(AX) = 0x05;
1.1.1.3 root 7054: m_CF = 1;
1.1 root 7055: }
7056: } else {
7057: REG16(AX) = 0x06;
1.1.1.3 root 7058: m_CF = 1;
1.1 root 7059: }
7060: }
7061:
7062: inline void msdos_int_21h_41h(int lfn)
7063: {
1.1.1.3 root 7064: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 7065: REG16(AX) = errno;
1.1.1.3 root 7066: m_CF = 1;
1.1 root 7067: }
7068: }
7069:
7070: inline void msdos_int_21h_42h()
7071: {
7072: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7073: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7074:
1.1.1.20 root 7075: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 7076: if(REG8(AL) < 0x03) {
7077: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 7078: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
7079: UINT32 pos = _tell(fd);
1.1 root 7080: REG16(AX) = pos & 0xffff;
7081: REG16(DX) = (pos >> 16);
7082: } else {
7083: REG16(AX) = 0x01;
1.1.1.3 root 7084: m_CF = 1;
1.1 root 7085: }
7086: } else {
7087: REG16(AX) = 0x06;
1.1.1.3 root 7088: m_CF = 1;
1.1 root 7089: }
7090: }
7091:
7092: inline void msdos_int_21h_43h(int lfn)
7093: {
1.1.1.3 root 7094: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 7095: int attr;
7096:
1.1.1.14 root 7097: if(!lfn && REG8(AL) > 2) {
7098: REG16(AX) = 0x01;
7099: m_CF = 1;
7100: return;
7101: }
7102: switch(REG8(lfn ? BL : AL)) {
1.1 root 7103: case 0x00:
7104: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 7105: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
7106: } else {
7107: REG16(AX) = (UINT16)GetLastError();
7108: m_CF = 1;
7109: }
7110: break;
7111: case 0x01:
7112: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
7113: REG16(AX) = (UINT16)GetLastError();
7114: m_CF = 1;
7115: }
7116: break;
7117: case 0x02:
7118: {
7119: DWORD size = GetCompressedFileSize(path, NULL);
7120: if(size != INVALID_FILE_SIZE) {
7121: if(size != 0 && size == GetFileSize(path, NULL)) {
7122: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
7123: // this isn't correct if the file is in the NTFS MFT
7124: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
7125: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
7126: }
7127: }
7128: REG16(AX) = LOWORD(size);
7129: REG16(DX) = HIWORD(size);
7130: } else {
7131: REG16(AX) = (UINT16)GetLastError();
7132: m_CF = 1;
1.1 root 7133: }
1.1.1.14 root 7134: }
7135: break;
7136: case 0x03:
7137: case 0x05:
7138: case 0x07:
7139: {
7140: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7141: if(hFile != INVALID_HANDLE_VALUE) {
7142: FILETIME local, time;
7143: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
7144: if(REG8(BL) == 7) {
7145: ULARGE_INTEGER hund;
7146: hund.LowPart = local.dwLowDateTime;
7147: hund.HighPart = local.dwHighDateTime;
7148: hund.QuadPart += REG16(SI) * 100000;
7149: local.dwLowDateTime = hund.LowPart;
7150: local.dwHighDateTime = hund.HighPart;
7151: }
7152: LocalFileTimeToFileTime(&local, &time);
7153: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
7154: REG8(BL) == 0x05 ? &time : NULL,
7155: REG8(BL) == 0x03 ? &time : NULL)) {
7156: REG16(AX) = (UINT16)GetLastError();
7157: m_CF = 1;
7158: }
7159: CloseHandle(hFile);
7160: } else {
7161: REG16(AX) = (UINT16)GetLastError();
7162: m_CF = 1;
1.1 root 7163: }
1.1.1.14 root 7164: }
7165: break;
7166: case 0x04:
7167: case 0x06:
7168: case 0x08:
7169: {
7170: WIN32_FILE_ATTRIBUTE_DATA fad;
7171: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
7172: FILETIME *time, local;
7173: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
7174: 0x06 ? &fad.ftLastAccessTime :
7175: &fad.ftCreationTime;
7176: FileTimeToLocalFileTime(time, &local);
7177: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
7178: if(REG8(BL) == 0x08) {
7179: ULARGE_INTEGER hund;
7180: hund.LowPart = local.dwLowDateTime;
7181: hund.HighPart = local.dwHighDateTime;
7182: hund.QuadPart /= 100000;
7183: REG16(SI) = (UINT16)(hund.QuadPart % 200);
7184: }
7185: } else {
7186: REG16(AX) = (UINT16)GetLastError();
7187: m_CF = 1;
1.1 root 7188: }
1.1.1.14 root 7189: }
7190: break;
7191: default:
1.1.1.22 root 7192: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 7193: REG16(AX) = 0x01;
7194: m_CF = 1;
7195: break;
7196: }
7197: }
7198:
7199: inline void msdos_int_21h_44h()
7200: {
1.1.1.22 root 7201: static UINT16 iteration_count = 0;
7202:
1.1.1.20 root 7203: process_t *process = msdos_process_info_get(current_psp);
7204: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7205:
1.1.1.14 root 7206: UINT32 val = DRIVE_NO_ROOT_DIR;
7207:
7208: switch(REG8(AL)) {
7209: case 0x00:
7210: case 0x01:
7211: case 0x02:
7212: case 0x03:
7213: case 0x04:
7214: case 0x05:
7215: case 0x06:
7216: case 0x07:
1.1.1.20 root 7217: if(fd >= process->max_files || !file_handler[fd].valid) {
7218: REG16(AX) = 0x06;
7219: m_CF = 1;
7220: return;
1.1.1.14 root 7221: }
7222: break;
7223: case 0x08:
7224: case 0x09:
7225: if(REG8(BL) >= ('Z' - 'A' + 1)) {
7226: // invalid drive number
7227: REG16(AX) = 0x0f;
7228: m_CF = 1;
7229: return;
7230: } else {
7231: if(REG8(BL) == 0) {
7232: val = GetDriveType(NULL);
7233: } else {
7234: char tmp[8];
7235: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
7236: val = GetDriveType(tmp);
7237: }
7238: if(val == DRIVE_NO_ROOT_DIR) {
7239: // no drive
7240: REG16(AX) = 0x0f;
7241: m_CF = 1;
7242: return;
1.1 root 7243: }
7244: }
7245: break;
7246: }
7247: switch(REG8(AL)) {
7248: case 0x00: // get ioctrl data
1.1.1.20 root 7249: REG16(DX) = file_handler[fd].info;
1.1 root 7250: break;
7251: case 0x01: // set ioctrl data
1.1.1.20 root 7252: file_handler[fd].info |= REG8(DL);
1.1 root 7253: break;
7254: case 0x02: // recv from character device
7255: case 0x03: // send to character device
7256: case 0x04: // recv from block device
7257: case 0x05: // send to block device
7258: REG16(AX) = 0x05;
1.1.1.3 root 7259: m_CF = 1;
1.1 root 7260: break;
7261: case 0x06: // get read status
1.1.1.20 root 7262: if(file_mode[file_handler[fd].mode].in) {
7263: if(file_handler[fd].atty) {
1.1.1.14 root 7264: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 7265: } else {
1.1.1.20 root 7266: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 7267: }
1.1.1.14 root 7268: } else {
7269: REG8(AL) = 0x00;
1.1 root 7270: }
7271: break;
7272: case 0x07: // get write status
1.1.1.20 root 7273: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 7274: REG8(AL) = 0xff;
7275: } else {
7276: REG8(AL) = 0x00;
1.1 root 7277: }
7278: break;
7279: case 0x08: // check removable drive
1.1.1.14 root 7280: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
7281: // removable drive
7282: REG16(AX) = 0x00;
1.1 root 7283: } else {
1.1.1.14 root 7284: // fixed drive
7285: REG16(AX) = 0x01;
1.1 root 7286: }
7287: break;
7288: case 0x09: // check remote drive
1.1.1.14 root 7289: if(val == DRIVE_REMOTE) {
7290: // remote drive
7291: REG16(DX) = 0x1000;
1.1 root 7292: } else {
1.1.1.14 root 7293: // local drive
7294: REG16(DX) = 0x00;
1.1 root 7295: }
7296: break;
1.1.1.21 root 7297: case 0x0a: // check remote handle
7298: REG16(DX) = 0x00; // FIXME
7299: break;
1.1 root 7300: case 0x0b: // set retry count
7301: break;
1.1.1.22 root 7302: case 0x0c: // generic character device request
7303: if(REG8(CL) == 0x45) {
7304: // set iteration (retry) count
7305: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
7306: } else if(REG8(CL) == 0x4a) {
7307: // select code page
7308: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
7309: msdos_nls_tables_update();
7310: } else if(REG8(CL) == 0x65) {
7311: // get iteration (retry) count
7312: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
7313: } else if(REG8(CL) == 0x6a) {
7314: // query selected code page
7315: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
7316: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
7317:
7318: CPINFO info;
7319: GetCPInfo(active_code_page, &info);
7320:
7321: if(info.MaxCharSize != 1) {
7322: for(int i = 0;; i++) {
7323: UINT8 lo = info.LeadByte[2 * i + 0];
7324: UINT8 hi = info.LeadByte[2 * i + 1];
7325:
7326: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
7327: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
7328: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
7329:
7330: if(lo == 0 && hi == 0) {
7331: break;
7332: }
7333: }
7334: }
7335: } else if(REG8(CL) == 0x7f) {
7336: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
7337: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
7338: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
7339: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
7340: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
7341: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
7342: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
7343: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
7344: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
7345: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
7346: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
7347: } else {
7348: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
7349: REG16(AX) = 0x01; // invalid function
7350: m_CF = 1;
7351: }
7352: break;
7353: case 0x0d: // generic block device request
7354: if(REG8(CL) == 0x40) {
7355: // set device parameters
7356: } else if(REG8(CL) == 0x46) {
7357: // set volume serial number
7358: } else if(REG8(CL) == 0x4a) {
7359: // lock logical volume
7360: } else if(REG8(CL) == 0x4b) {
7361: // lock physical volume
7362: } else if(REG8(CL) == 0x60) {
7363: // get device parameters
7364: char dev[] = "\\\\.\\A:";
7365: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
7366:
7367: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7368: if(hFile != INVALID_HANDLE_VALUE) {
7369: DISK_GEOMETRY geo;
7370: DWORD dwSize;
7371: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
7372: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
7373: switch(geo.MediaType) {
7374: case F5_360_512:
7375: case F5_320_512:
7376: case F5_320_1024:
7377: case F5_180_512:
7378: case F5_160_512:
7379: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
7380: break;
7381: case F5_1Pt2_512:
7382: case F3_1Pt2_512:
7383: case F3_1Pt23_1024:
7384: case F5_1Pt23_1024:
7385: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
7386: break;
7387: case F3_720_512:
7388: case F3_640_512:
7389: case F5_640_512:
7390: case F5_720_512:
7391: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
7392: break;
7393: case F8_256_128:
7394: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
7395: break;
7396: case FixedMedia:
7397: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
7398: break;
7399: case F3_1Pt44_512:
7400: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
7401: break;
7402: case F3_2Pt88_512:
7403: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
7404: break;
7405: default:
7406: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
7407: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
7408: break;
7409: }
7410: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
7411: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
7412: switch(geo.MediaType) {
7413: case F5_360_512:
7414: case F5_320_512:
7415: case F5_320_1024:
7416: case F5_180_512:
7417: case F5_160_512:
7418: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
7419: break;
7420: default:
7421: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
7422: break;
7423: }
7424: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
7425: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
7426: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
7427: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
7428: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
7429: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
7430: switch(geo.MediaType) {
7431: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
7432: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
7433: break;
7434: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
7435: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
7436: break;
7437: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
7438: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
7439: break;
7440: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
7441: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
7442: break;
7443: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
7444: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
7445: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
7446: break;
7447: case FixedMedia: // hard disk
7448: case RemovableMedia:
7449: case Unknown:
7450: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
7451: break;
7452: default:
7453: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
7454: break;
7455: }
7456: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
7457: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
7458: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
7459: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
7460: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
7461: // 21h BYTE device type
7462: // 22h WORD device attributes (removable or not, etc)
7463: } else {
7464: REG16(AX) = 0x0f; // invalid drive
7465: m_CF = 1;
7466: }
7467: CloseHandle(hFile);
7468: } else {
7469: REG16(AX) = 0x0f; // invalid drive
7470: m_CF = 1;
7471: }
7472: } else if(REG8(CL) == 0x66) {
7473: // get volume serial number
7474: char path[] = "A:\\";
7475: char volume_label[MAX_PATH];
7476: DWORD serial_number = 0;
7477: char file_system[MAX_PATH];
7478:
7479: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
7480:
7481: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
7482: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
7483: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
7484: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
7485: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
7486: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
7487: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
7488: } else {
7489: REG16(AX) = 0x0f; // invalid drive
7490: m_CF = 1;
7491: }
7492: } else if(REG8(CL) == 0x67) {
7493: // get access flag
7494: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
7495: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
7496: } else if(REG8(CL) == 0x68) {
7497: // sense media type
7498: char dev[64];
7499: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7500:
7501: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7502: if(hFile != INVALID_HANDLE_VALUE) {
7503: DISK_GEOMETRY geo;
7504: DWORD dwSize;
7505: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
7506: switch(geo.MediaType) {
7507: case F3_720_512:
7508: case F5_720_512:
7509: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
7510: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
7511: break;
7512: case F3_1Pt44_512:
7513: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
7514: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
7515: break;
7516: case F3_2Pt88_512:
7517: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
7518: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
7519: break;
7520: default:
7521: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
7522: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
7523: break;
7524: }
7525: } else {
7526: REG16(AX) = 0x0f; // invalid drive
7527: m_CF = 1;
7528: }
7529: CloseHandle(hFile);
7530: } else {
7531: REG16(AX) = 0x0f; // invalid drive
7532: m_CF = 1;
7533: }
7534: } else if(REG8(CL) == 0x6a) {
7535: // unlock logical volume
7536: } else if(REG8(CL) == 0x6b) {
7537: // unlock physical volume
7538: } else {
7539: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
7540: REG16(AX) = 0x01; // invalid function
7541: m_CF = 1;
7542: }
7543: break;
7544: case 0x0e: // get logical drive map
7545: {
7546: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7547: if(!(GetLogicalDrives() & bits)) {
7548: REG16(AX) = 0x0f; // invalid drive
7549: m_CF = 1;
7550: } else {
7551: REG8(AL) = 0;
7552: }
7553: }
7554: break;
7555: case 0x0f: // set logical drive map
7556: {
7557: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7558: if(!(GetLogicalDrives() & bits)) {
7559: REG16(AX) = 0x0f; // invalid drive
7560: m_CF = 1;
7561: }
7562: }
7563: break;
7564: case 0x10: // query generic ioctrl capability (handle)
7565: switch(REG8(CL)) {
7566: case 0x45:
7567: case 0x4a:
7568: case 0x65:
7569: case 0x6a:
7570: case 0x7f:
7571: REG16(AX) = 0x0000; // supported
7572: break;
7573: default:
7574: REG8(AL) = 0x01; // ioctl capability not available
7575: m_CF = 1;
7576: break;
7577: }
7578: break;
7579: case 0x11: // query generic ioctrl capability (drive)
7580: switch(REG8(CL)) {
7581: case 0x40:
7582: case 0x46:
7583: case 0x4a:
7584: case 0x4b:
7585: case 0x60:
7586: case 0x66:
7587: case 0x67:
7588: case 0x68:
7589: case 0x6a:
7590: case 0x6b:
7591: REG16(AX) = 0x0000; // supported
7592: break;
7593: default:
7594: REG8(AL) = 0x01; // ioctl capability not available
7595: m_CF = 1;
7596: break;
7597: }
7598: break;
7599: case 0x12: // determine dos type
7600: case 0x51: // concurrent dos v3.2+ - installation check
7601: case 0x52: // determine dos type/get dr dos versuin
7602: REG16(AX) = 0x01; // this is not DR-DOS
7603: m_CF = 1;
7604: break;
1.1 root 7605: default:
1.1.1.22 root 7606: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 7607: REG16(AX) = 0x01;
1.1.1.3 root 7608: m_CF = 1;
1.1 root 7609: break;
7610: }
7611: }
7612:
7613: inline void msdos_int_21h_45h()
7614: {
7615: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7616: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7617:
1.1.1.20 root 7618: if(fd < process->max_files && file_handler[fd].valid) {
7619: int dup_fd = _dup(fd);
7620: if(dup_fd != -1) {
7621: REG16(AX) = dup_fd;
7622: msdos_file_handler_dup(dup_fd, fd, current_psp);
7623: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
7624: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 7625: } else {
7626: REG16(AX) = errno;
1.1.1.3 root 7627: m_CF = 1;
1.1 root 7628: }
7629: } else {
7630: REG16(AX) = 0x06;
1.1.1.3 root 7631: m_CF = 1;
1.1 root 7632: }
7633: }
7634:
7635: inline void msdos_int_21h_46h()
7636: {
7637: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7638: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7639: int dup_fd = REG16(CX);
7640: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 7641:
1.1.1.20 root 7642: if(REG16(BX) == REG16(CX)) {
7643: REG16(AX) = 0x06;
7644: m_CF = 1;
7645: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
7646: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
7647: _close(tmp_fd);
7648: msdos_file_handler_close(tmp_fd);
7649: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
7650: }
7651: if(_dup2(fd, dup_fd) != -1) {
7652: msdos_file_handler_dup(dup_fd, fd, current_psp);
7653: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
7654: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 7655: } else {
7656: REG16(AX) = errno;
1.1.1.3 root 7657: m_CF = 1;
1.1 root 7658: }
7659: } else {
7660: REG16(AX) = 0x06;
1.1.1.3 root 7661: m_CF = 1;
1.1 root 7662: }
7663: }
7664:
7665: inline void msdos_int_21h_47h(int lfn)
7666: {
7667: char path[MAX_PATH];
7668:
7669: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
7670: if(path[1] == ':') {
7671: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 7672: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 7673: } else {
1.1.1.3 root 7674: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 7675: }
7676: } else {
7677: REG16(AX) = errno;
1.1.1.3 root 7678: m_CF = 1;
1.1 root 7679: }
7680: }
7681:
7682: inline void msdos_int_21h_48h()
7683: {
1.1.1.19 root 7684: int seg, umb_linked;
1.1 root 7685:
1.1.1.8 root 7686: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 7687: // unlink umb not to allocate memory in umb
7688: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
7689: msdos_mem_unlink_umb();
7690: }
1.1.1.8 root 7691: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
7692: REG16(AX) = seg;
7693: } else {
7694: REG16(AX) = 0x08;
7695: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
7696: m_CF = 1;
7697: }
1.1.1.19 root 7698: if(umb_linked != 0) {
7699: msdos_mem_link_umb();
7700: }
1.1.1.8 root 7701: } else if((malloc_strategy & 0xf0) == 0x40) {
7702: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
7703: REG16(AX) = seg;
7704: } else {
7705: REG16(AX) = 0x08;
7706: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
7707: m_CF = 1;
7708: }
7709: } else if((malloc_strategy & 0xf0) == 0x80) {
7710: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
7711: REG16(AX) = seg;
7712: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
7713: REG16(AX) = seg;
7714: } else {
7715: REG16(AX) = 0x08;
7716: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
7717: m_CF = 1;
7718: }
1.1 root 7719: }
7720: }
7721:
7722: inline void msdos_int_21h_49h()
7723: {
1.1.1.14 root 7724: int mcb_seg = SREG(ES) - 1;
7725: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
7726:
7727: if(mcb->mz == 'M' || mcb->mz == 'Z') {
7728: msdos_mem_free(SREG(ES));
7729: } else {
1.1.1.28 root 7730: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 7731: m_CF = 1;
7732: }
1.1 root 7733: }
7734:
7735: inline void msdos_int_21h_4ah()
7736: {
1.1.1.14 root 7737: int mcb_seg = SREG(ES) - 1;
7738: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 7739: int max_paragraphs;
7740:
1.1.1.14 root 7741: if(mcb->mz == 'M' || mcb->mz == 'Z') {
7742: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
7743: REG16(AX) = 0x08;
7744: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
7745: m_CF = 1;
7746: }
7747: } else {
1.1.1.28 root 7748: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 7749: m_CF = 1;
1.1 root 7750: }
7751: }
7752:
7753: inline void msdos_int_21h_4bh()
7754: {
1.1.1.3 root 7755: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7756: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 7757:
7758: switch(REG8(AL)) {
7759: case 0x00:
7760: case 0x01:
7761: if(msdos_process_exec(command, param, REG8(AL))) {
7762: REG16(AX) = 0x02;
1.1.1.3 root 7763: m_CF = 1;
1.1 root 7764: }
7765: break;
1.1.1.14 root 7766: case 0x03:
7767: {
7768: int fd;
7769: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
7770: REG16(AX) = 0x02;
7771: m_CF = 1;
7772: break;
7773: }
7774: int size = _read(fd, file_buffer, sizeof(file_buffer));
7775: _close(fd);
7776:
7777: UINT16 *overlay = (UINT16 *)param;
7778:
7779: // check exe header
7780: exe_header_t *header = (exe_header_t *)file_buffer;
7781: int header_size = 0;
7782: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
7783: header_size = header->header_size * 16;
7784: // relocation
7785: int start_seg = overlay[1];
7786: for(int i = 0; i < header->relocations; i++) {
7787: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
7788: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
7789: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
7790: }
7791: }
7792: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
7793: }
7794: break;
1.1 root 7795: default:
1.1.1.22 root 7796: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 7797: REG16(AX) = 0x01;
1.1.1.3 root 7798: m_CF = 1;
1.1 root 7799: break;
7800: }
7801: }
7802:
7803: inline void msdos_int_21h_4ch()
7804: {
7805: msdos_process_terminate(current_psp, REG8(AL), 1);
7806: }
7807:
7808: inline void msdos_int_21h_4dh()
7809: {
7810: REG16(AX) = retval;
7811: }
7812:
7813: inline void msdos_int_21h_4eh()
7814: {
7815: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7816: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7817: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 7818: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 7819: WIN32_FIND_DATA fd;
7820:
1.1.1.14 root 7821: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7822: find->find_magic = FIND_MAGIC;
7823: find->dta_index = dtainfo - dtalist;
1.1 root 7824: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7825: dtainfo->allowable_mask = REG8(CL);
7826: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7827:
1.1.1.14 root 7828: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7829: dtainfo->allowable_mask &= ~8;
1.1 root 7830: }
1.1.1.14 root 7831: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7832: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7833: !msdos_find_file_has_8dot3name(&fd)) {
7834: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7835: FindClose(dtainfo->find_handle);
7836: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7837: break;
7838: }
7839: }
7840: }
1.1.1.13 root 7841: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7842: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
7843: msdos_find_file_conv_local_time(&fd);
7844: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
7845: find->size = fd.nFileSizeLow;
1.1.1.13 root 7846: strcpy(find->name, msdos_short_name(&fd));
1.1 root 7847: REG16(AX) = 0;
1.1.1.14 root 7848: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7849: find->attrib = 8;
7850: find->size = 0;
7851: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7852: dtainfo->allowable_mask &= ~8;
1.1 root 7853: REG16(AX) = 0;
7854: } else {
7855: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7856: m_CF = 1;
1.1 root 7857: }
7858: }
7859:
7860: inline void msdos_int_21h_4fh()
7861: {
7862: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7863: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7864: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 7865: WIN32_FIND_DATA fd;
7866:
1.1.1.14 root 7867: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
7868: REG16(AX) = 0x12;
7869: m_CF = 1;
7870: return;
7871: }
7872: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 7873: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7874: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7875: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7876: !msdos_find_file_has_8dot3name(&fd)) {
7877: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7878: FindClose(dtainfo->find_handle);
7879: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7880: break;
7881: }
7882: }
7883: } else {
1.1.1.13 root 7884: FindClose(dtainfo->find_handle);
7885: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7886: }
7887: }
1.1.1.13 root 7888: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7889: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
7890: msdos_find_file_conv_local_time(&fd);
7891: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
7892: find->size = fd.nFileSizeLow;
1.1.1.13 root 7893: strcpy(find->name, msdos_short_name(&fd));
1.1 root 7894: REG16(AX) = 0;
1.1.1.14 root 7895: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7896: find->attrib = 8;
7897: find->size = 0;
7898: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7899: dtainfo->allowable_mask &= ~8;
1.1 root 7900: REG16(AX) = 0;
7901: } else {
7902: REG16(AX) = 0x12;
1.1.1.3 root 7903: m_CF = 1;
1.1 root 7904: }
7905: }
7906:
7907: inline void msdos_int_21h_50h()
7908: {
1.1.1.8 root 7909: if(current_psp != REG16(BX)) {
7910: process_t *process = msdos_process_info_get(current_psp);
7911: if(process != NULL) {
7912: process->psp = REG16(BX);
7913: }
7914: current_psp = REG16(BX);
1.1.1.23 root 7915: msdos_sda_update(current_psp);
1.1.1.8 root 7916: }
1.1 root 7917: }
7918:
7919: inline void msdos_int_21h_51h()
7920: {
7921: REG16(BX) = current_psp;
7922: }
7923:
7924: inline void msdos_int_21h_52h()
7925: {
1.1.1.25 root 7926: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 7927: i386_load_segment_descriptor(ES);
1.1.1.25 root 7928: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 7929: }
7930:
7931: inline void msdos_int_21h_54h()
7932: {
7933: process_t *process = msdos_process_info_get(current_psp);
7934:
7935: REG8(AL) = process->verify;
7936: }
7937:
7938: inline void msdos_int_21h_55h()
7939: {
7940: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
7941:
7942: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
7943: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
7944: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
7945: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
7946: psp->parent_psp = current_psp;
7947: }
7948:
7949: inline void msdos_int_21h_56h(int lfn)
7950: {
7951: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 7952: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
7953: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 7954:
7955: if(rename(src, dst)) {
7956: REG16(AX) = errno;
1.1.1.3 root 7957: m_CF = 1;
1.1 root 7958: }
7959: }
7960:
7961: inline void msdos_int_21h_57h()
7962: {
7963: FILETIME time, local;
1.1.1.14 root 7964: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 7965: HANDLE hHandle;
1.1 root 7966:
1.1.1.21 root 7967: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 7968: REG16(AX) = (UINT16)GetLastError();
7969: m_CF = 1;
7970: return;
7971: }
7972: ctime = atime = mtime = NULL;
7973:
1.1 root 7974: switch(REG8(AL)) {
7975: case 0x00:
1.1.1.6 root 7976: case 0x01:
1.1.1.14 root 7977: mtime = &time;
1.1.1.6 root 7978: break;
7979: case 0x04:
7980: case 0x05:
1.1.1.14 root 7981: atime = &time;
1.1 root 7982: break;
1.1.1.6 root 7983: case 0x06:
7984: case 0x07:
1.1.1.14 root 7985: ctime = &time;
7986: break;
7987: default:
1.1.1.22 root 7988: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 7989: REG16(AX) = 0x01;
7990: m_CF = 1;
7991: return;
7992: }
7993: if(REG8(AL) & 1) {
1.1 root 7994: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
7995: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 7996: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 7997: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7998: m_CF = 1;
1.1 root 7999: }
1.1.1.14 root 8000: } else {
1.1.1.21 root 8001: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 8002: // assume a device and use the current time
8003: GetSystemTimeAsFileTime(&time);
8004: }
8005: FileTimeToLocalFileTime(&time, &local);
8006: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 8007: }
8008: }
8009:
8010: inline void msdos_int_21h_58h()
8011: {
8012: switch(REG8(AL)) {
8013: case 0x00:
1.1.1.7 root 8014: REG16(AX) = malloc_strategy;
8015: break;
8016: case 0x01:
1.1.1.24 root 8017: // switch(REG16(BX)) {
8018: switch(REG8(BL)) {
1.1.1.7 root 8019: case 0x0000:
8020: case 0x0001:
8021: case 0x0002:
8022: case 0x0040:
8023: case 0x0041:
8024: case 0x0042:
8025: case 0x0080:
8026: case 0x0081:
8027: case 0x0082:
8028: malloc_strategy = REG16(BX);
1.1.1.23 root 8029: msdos_sda_update(current_psp);
1.1.1.7 root 8030: break;
8031: default:
1.1.1.22 root 8032: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.7 root 8033: REG16(AX) = 0x01;
8034: m_CF = 1;
8035: break;
8036: }
8037: break;
8038: case 0x02:
1.1.1.19 root 8039: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 8040: break;
8041: case 0x03:
1.1.1.24 root 8042: // switch(REG16(BX)) {
8043: switch(REG8(BL)) {
1.1.1.7 root 8044: case 0x0000:
1.1.1.19 root 8045: msdos_mem_unlink_umb();
8046: break;
1.1.1.7 root 8047: case 0x0001:
1.1.1.19 root 8048: msdos_mem_link_umb();
1.1.1.7 root 8049: break;
8050: default:
1.1.1.22 root 8051: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.7 root 8052: REG16(AX) = 0x01;
8053: m_CF = 1;
8054: break;
8055: }
1.1 root 8056: break;
8057: default:
1.1.1.22 root 8058: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8059: REG16(AX) = 0x01;
1.1.1.3 root 8060: m_CF = 1;
1.1 root 8061: break;
8062: }
8063: }
8064:
8065: inline void msdos_int_21h_59h()
8066: {
1.1.1.23 root 8067: sda_t *sda = (sda_t *)(mem + SDA_TOP);
8068:
8069: REG16(AX) = sda->extended_error_code;
8070: REG8(BH) = sda->error_class;
8071: REG8(BL) = sda->suggested_action;
8072: REG8(CH) = sda->locus_of_last_error;
1.1 root 8073: }
8074:
8075: inline void msdos_int_21h_5ah()
8076: {
1.1.1.3 root 8077: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8078: int len = strlen(path);
8079: char tmp[MAX_PATH];
8080:
8081: if(GetTempFileName(path, "TMP", 0, tmp)) {
8082: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
8083:
8084: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
8085: REG16(AX) = fd;
8086: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 8087: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8088:
8089: strcpy(path, tmp);
8090: int dx = REG16(DX) + len;
1.1.1.3 root 8091: int ds = SREG(DS);
1.1 root 8092: while(dx > 0xffff) {
8093: dx -= 0x10;
8094: ds++;
8095: }
8096: REG16(DX) = dx;
1.1.1.3 root 8097: SREG(DS) = ds;
8098: i386_load_segment_descriptor(DS);
1.1 root 8099: } else {
8100: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8101: m_CF = 1;
1.1 root 8102: }
8103: }
8104:
8105: inline void msdos_int_21h_5bh()
8106: {
1.1.1.3 root 8107: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 8108:
1.1.1.24 root 8109: if(msdos_is_existing_file(path)) {
1.1 root 8110: // already exists
8111: REG16(AX) = 0x50;
1.1.1.3 root 8112: m_CF = 1;
1.1 root 8113: } else {
8114: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
8115:
8116: if(fd != -1) {
8117: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
8118: REG16(AX) = fd;
8119: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 8120: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8121: } else {
8122: REG16(AX) = errno;
1.1.1.3 root 8123: m_CF = 1;
1.1 root 8124: }
8125: }
8126: }
8127:
8128: inline void msdos_int_21h_5ch()
8129: {
8130: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8131: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8132:
1.1.1.20 root 8133: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 8134: if(REG8(AL) == 0 || REG8(AL) == 1) {
8135: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 8136: UINT32 pos = _tell(fd);
8137: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
8138: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 8139: REG16(AX) = errno;
1.1.1.3 root 8140: m_CF = 1;
1.1 root 8141: }
1.1.1.20 root 8142: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 8143:
1.1 root 8144: // some seconds may be passed in _locking()
8145: hardware_update();
8146: } else {
8147: REG16(AX) = 0x01;
1.1.1.3 root 8148: m_CF = 1;
1.1 root 8149: }
8150: } else {
8151: REG16(AX) = 0x06;
1.1.1.3 root 8152: m_CF = 1;
1.1 root 8153: }
8154: }
8155:
1.1.1.22 root 8156: inline void msdos_int_21h_5dh()
8157: {
8158: switch(REG8(AL)) {
8159: case 0x06: // get address of dos swappable data area
1.1.1.23 root 8160: SREG(DS) = (SDA_TOP >> 4);
8161: i386_load_segment_descriptor(DS);
8162: REG16(SI) = offsetof(sda_t, crit_error_flag);
8163: REG16(CX) = 0x80;
8164: REG16(DX) = 0x1a;
8165: break;
8166: case 0x0b: // get dos swappable data areas
1.1.1.22 root 8167: REG16(AX) = 0x01;
8168: m_CF = 1;
8169: break;
8170: case 0x08: // set redirected printer mode
8171: case 0x09: // flush redirected printer output
8172: case 0x0a: // set extended error information
8173: break;
8174: default:
8175: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8176: REG16(AX) = 0x01;
8177: m_CF = 1;
8178: break;
8179: }
8180: }
8181:
1.1.1.30 root 8182: inline void msdos_int_21h_5fh()
8183: {
8184: switch(REG8(AL)) {
8185: case 0x02:
8186: {
8187: DWORD drives = GetLogicalDrives();
8188: for(int i = 0, index = 0; i < 26; i++) {
8189: if(drives & (1 << i)) {
8190: char volume[] = "A:\\";
8191: volume[0] = 'A' + i;
8192: if(GetDriveType(volume) == DRIVE_REMOTE) {
8193: if(index == REG16(BX)) {
8194: DWORD dwSize = 128;
8195: volume[2] = '\0';
8196: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
8197: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
8198: REG8(BH) = 0x00; // valid
8199: REG8(BL) = 0x04; // disk drive
8200: REG16(CX) = 0x00;
8201: return;
8202: }
8203: index++;
8204: }
8205: }
8206: }
8207: }
8208: REG16(AX) = 0x12; // no more files
8209: m_CF = 1;
8210: break;
8211: default:
8212: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8213: REG16(AX) = 0x01;
8214: m_CF = 1;
8215: break;
8216: }
8217: }
8218:
1.1 root 8219: inline void msdos_int_21h_60h(int lfn)
8220: {
1.1.1.14 root 8221: char full[MAX_PATH], *path;
8222:
1.1 root 8223: if(lfn) {
1.1.1.14 root 8224: char *name;
8225: *full = '\0';
1.1.1.3 root 8226: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 8227: switch(REG8(CL)) {
8228: case 1:
8229: GetShortPathName(full, full, MAX_PATH);
8230: my_strupr(full);
8231: break;
8232: case 2:
8233: GetLongPathName(full, full, MAX_PATH);
8234: break;
8235: }
8236: path = full;
8237: } else {
8238: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
8239: }
8240: if(*path != '\0') {
8241: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 8242: } else {
1.1.1.14 root 8243: REG16(AX) = (UINT16)GetLastError();
8244: m_CF = 1;
1.1 root 8245: }
8246: }
8247:
8248: inline void msdos_int_21h_61h()
8249: {
8250: REG8(AL) = 0;
8251: }
8252:
8253: inline void msdos_int_21h_62h()
8254: {
8255: REG16(BX) = current_psp;
8256: }
8257:
8258: inline void msdos_int_21h_63h()
8259: {
8260: switch(REG8(AL)) {
8261: case 0x00:
1.1.1.3 root 8262: SREG(DS) = (DBCS_TABLE >> 4);
8263: i386_load_segment_descriptor(DS);
1.1 root 8264: REG16(SI) = (DBCS_TABLE & 0x0f);
8265: REG8(AL) = 0x00;
8266: break;
1.1.1.22 root 8267: case 0x01: // set korean input mode
8268: case 0x02: // get korean input mode
8269: REG8(AL) = 0xff; // not supported
8270: break;
1.1 root 8271: default:
1.1.1.22 root 8272: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8273: REG16(AX) = 0x01;
1.1.1.3 root 8274: m_CF = 1;
1.1 root 8275: break;
8276: }
8277: }
8278:
1.1.1.25 root 8279: UINT16 get_extended_country_info(UINT8 func)
1.1 root 8280: {
1.1.1.25 root 8281: switch(func) {
1.1.1.17 root 8282: case 0x01:
8283: if(REG16(CX) >= 5) {
1.1.1.19 root 8284: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 8285: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
8286: REG16(CX) = sizeof(data);
8287: ZeroMemory(data, sizeof(data));
8288: data[0] = 0x01;
8289: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 8290: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 8291: *(UINT16 *)(data + 5) = active_code_page;
8292: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 8293: // REG16(AX) = active_code_page;
1.1.1.17 root 8294: } else {
1.1.1.25 root 8295: return(0x08); // insufficient memory
1.1.1.17 root 8296: }
8297: break;
8298: case 0x02:
8299: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
8300: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
8301: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 8302: // REG16(AX) = active_code_page;
1.1.1.17 root 8303: REG16(CX) = 0x05;
8304: break;
1.1.1.23 root 8305: case 0x03:
8306: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
8307: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
8308: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 8309: // REG16(AX) = active_code_page;
1.1.1.23 root 8310: REG16(CX) = 0x05;
8311: break;
1.1.1.17 root 8312: case 0x04:
8313: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
8314: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
8315: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 8316: // REG16(AX) = active_code_page;
1.1.1.17 root 8317: REG16(CX) = 0x05;
8318: break;
8319: case 0x05:
8320: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
8321: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
8322: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 8323: // REG16(AX) = active_code_page;
1.1.1.17 root 8324: REG16(CX) = 0x05;
8325: break;
8326: case 0x06:
8327: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
8328: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
8329: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 8330: // REG16(AX) = active_code_page;
1.1.1.17 root 8331: REG16(CX) = 0x05;
8332: break;
1.1 root 8333: case 0x07:
1.1.1.3 root 8334: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
8335: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
8336: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 8337: // REG16(AX) = active_code_page;
1.1 root 8338: REG16(CX) = 0x05;
8339: break;
1.1.1.25 root 8340: default:
8341: return(0x01); // function number invalid
8342: }
8343: return(0x00);
8344: }
8345:
8346: inline void msdos_int_21h_65h()
8347: {
8348: char tmp[0x10000];
8349:
8350: switch(REG8(AL)) {
8351: case 0x01:
8352: case 0x02:
8353: case 0x03:
8354: case 0x04:
8355: case 0x05:
8356: case 0x06:
8357: case 0x07:
8358: {
8359: UINT16 result = get_extended_country_info(REG8(AL));
8360: if(result) {
8361: REG16(AX) = result;
8362: m_CF = 1;
8363: } else {
8364: REG16(AX) = active_code_page; // FIXME: is this correct???
8365: }
8366: }
8367: break;
1.1 root 8368: case 0x20:
1.1.1.25 root 8369: case 0xa0:
1.1.1.19 root 8370: memset(tmp, 0, sizeof(tmp));
8371: tmp[0] = REG8(DL);
1.1 root 8372: my_strupr(tmp);
8373: REG8(DL) = tmp[0];
8374: break;
8375: case 0x21:
1.1.1.25 root 8376: case 0xa1:
1.1 root 8377: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 8378: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 8379: my_strupr(tmp);
1.1.1.3 root 8380: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 8381: break;
8382: case 0x22:
1.1.1.25 root 8383: case 0xa2:
1.1.1.3 root 8384: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 8385: break;
1.1.1.25 root 8386: case 0x23:
8387: // FIXME: need to check multi-byte (kanji) charactre?
8388: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
8389: // 8278h/8299h: multi-byte (kanji) Y and y
8390: REG16(AX) = 0x00;
8391: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
8392: // 826dh/828eh: multi-byte (kanji) N and n
8393: REG16(AX) = 0x01;
8394: } else {
8395: REG16(AX) = 0x02;
8396: }
8397: break;
1.1 root 8398: default:
1.1.1.22 root 8399: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8400: REG16(AX) = 0x01;
1.1.1.3 root 8401: m_CF = 1;
1.1 root 8402: break;
8403: }
8404: }
8405:
8406: inline void msdos_int_21h_66h()
8407: {
8408: switch(REG8(AL)) {
8409: case 0x01:
8410: REG16(BX) = active_code_page;
8411: REG16(DX) = system_code_page;
8412: break;
8413: case 0x02:
8414: if(active_code_page == REG16(BX)) {
8415: REG16(AX) = 0xeb41;
8416: } else if(_setmbcp(REG16(BX)) == 0) {
8417: active_code_page = REG16(BX);
1.1.1.17 root 8418: msdos_nls_tables_update();
1.1 root 8419: REG16(AX) = 0xeb41;
1.1.1.32! root 8420: SetConsoleCP(active_code_page);
! 8421: SetConsoleOutputCP(active_code_page);
1.1 root 8422: } else {
8423: REG16(AX) = 0x25;
1.1.1.3 root 8424: m_CF = 1;
1.1 root 8425: }
8426: break;
8427: default:
1.1.1.22 root 8428: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8429: REG16(AX) = 0x01;
1.1.1.3 root 8430: m_CF = 1;
1.1 root 8431: break;
8432: }
8433: }
8434:
8435: inline void msdos_int_21h_67h()
8436: {
8437: process_t *process = msdos_process_info_get(current_psp);
8438:
8439: if(REG16(BX) <= MAX_FILES) {
8440: process->max_files = max(REG16(BX), 20);
8441: } else {
8442: REG16(AX) = 0x08;
1.1.1.3 root 8443: m_CF = 1;
1.1 root 8444: }
8445: }
8446:
8447: inline void msdos_int_21h_68h()
8448: {
8449: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8450: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8451:
1.1.1.20 root 8452: if(fd < process->max_files && file_handler[fd].valid) {
8453: // fflush(_fdopen(fd, ""));
1.1 root 8454: } else {
8455: REG16(AX) = 0x06;
1.1.1.3 root 8456: m_CF = 1;
1.1 root 8457: }
8458: }
8459:
8460: inline void msdos_int_21h_69h()
8461: {
1.1.1.3 root 8462: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8463: char path[] = "A:\\";
8464: char volume_label[MAX_PATH];
8465: DWORD serial_number = 0;
8466: char file_system[MAX_PATH];
8467:
8468: if(REG8(BL) == 0) {
8469: path[0] = 'A' + _getdrive() - 1;
8470: } else {
8471: path[0] = 'A' + REG8(BL) - 1;
8472: }
8473:
8474: switch(REG8(AL)) {
8475: case 0x00:
8476: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
8477: info->info_level = 0;
8478: info->serial_number = serial_number;
8479: memset(info->volume_label, 0x20, 11);
8480: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
8481: memset(info->file_system, 0x20, 8);
8482: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
8483: } else {
8484: REG16(AX) = errno;
1.1.1.3 root 8485: m_CF = 1;
1.1 root 8486: }
8487: break;
8488: case 0x01:
8489: REG16(AX) = 0x03;
1.1.1.3 root 8490: m_CF = 1;
1.1 root 8491: }
8492: }
8493:
8494: inline void msdos_int_21h_6ah()
8495: {
8496: REG8(AH) = 0x68;
8497: msdos_int_21h_68h();
8498: }
8499:
8500: inline void msdos_int_21h_6bh()
8501: {
8502: REG8(AL) = 0;
8503: }
8504:
8505: inline void msdos_int_21h_6ch(int lfn)
8506: {
1.1.1.3 root 8507: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 8508: int mode = REG8(BL) & 0x03;
8509:
8510: if(mode < 0x03) {
1.1.1.29 root 8511: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 8512: // file exists
8513: if(REG8(DL) & 1) {
1.1.1.29 root 8514: int fd = -1, c;
1.1.1.11 root 8515: UINT16 info;
1.1 root 8516:
1.1.1.11 root 8517: if(msdos_is_con_path(path)) {
1.1.1.13 root 8518: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 8519: info = 0x80d3;
1.1.1.29 root 8520: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8521: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
8522: fd = msdos_open("NUL", file_mode[mode].mode);
8523: }
1.1.1.14 root 8524: info = 0x80d3;
1.1.1.29 root 8525: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8526: fd = msdos_open("NUL", file_mode[mode].mode);
8527: info = 0x80d3;
1.1.1.11 root 8528: } else {
1.1.1.13 root 8529: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 8530: info = msdos_drive_number(path);
8531: }
1.1 root 8532: if(fd != -1) {
8533: REG16(AX) = fd;
8534: REG16(CX) = 1;
1.1.1.11 root 8535: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 8536: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8537: } else {
8538: REG16(AX) = errno;
1.1.1.3 root 8539: m_CF = 1;
1.1 root 8540: }
8541: } else if(REG8(DL) & 2) {
8542: int attr = GetFileAttributes(path);
1.1.1.29 root 8543: int fd = -1, c;
1.1.1.11 root 8544: UINT16 info;
1.1 root 8545:
1.1.1.11 root 8546: if(msdos_is_con_path(path)) {
1.1.1.13 root 8547: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 8548: info = 0x80d3;
1.1.1.29 root 8549: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8550: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
8551: fd = msdos_open("NUL", file_mode[mode].mode);
8552: }
1.1.1.14 root 8553: info = 0x80d3;
1.1.1.29 root 8554: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8555: fd = msdos_open("NUL", file_mode[mode].mode);
8556: info = 0x80d3;
1.1 root 8557: } else {
8558: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 8559: info = msdos_drive_number(path);
1.1 root 8560: }
8561: if(fd != -1) {
8562: if(attr == -1) {
8563: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
8564: }
8565: SetFileAttributes(path, attr);
8566: REG16(AX) = fd;
8567: REG16(CX) = 3;
1.1.1.11 root 8568: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 8569: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8570: } else {
8571: REG16(AX) = errno;
1.1.1.3 root 8572: m_CF = 1;
1.1 root 8573: }
8574: } else {
8575: REG16(AX) = 0x50;
1.1.1.3 root 8576: m_CF = 1;
1.1 root 8577: }
8578: } else {
8579: // file not exists
8580: if(REG8(DL) & 0x10) {
8581: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
8582:
8583: if(fd != -1) {
8584: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
8585: REG16(AX) = fd;
8586: REG16(CX) = 2;
8587: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 8588: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8589: } else {
8590: REG16(AX) = errno;
1.1.1.3 root 8591: m_CF = 1;
1.1 root 8592: }
8593: } else {
8594: REG16(AX) = 0x02;
1.1.1.3 root 8595: m_CF = 1;
1.1 root 8596: }
8597: }
8598: } else {
8599: REG16(AX) = 0x0c;
1.1.1.3 root 8600: m_CF = 1;
1.1 root 8601: }
8602: }
8603:
8604: inline void msdos_int_21h_710dh()
8605: {
8606: // reset drive
8607: }
8608:
1.1.1.17 root 8609: inline void msdos_int_21h_7141h(int lfn)
8610: {
8611: if(REG16(SI) == 0) {
8612: msdos_int_21h_41h(lfn);
8613: return;
8614: }
8615: if(REG16(SI) != 1) {
8616: REG16(AX) = 5;
8617: m_CF = 1;
8618: }
8619: /* wild card and matching attributes... */
8620: char tmp[MAX_PATH * 2];
8621: // copy search pathname (and quick check overrun)
8622: ZeroMemory(tmp, sizeof(tmp));
8623: tmp[MAX_PATH - 1] = '\0';
8624: tmp[MAX_PATH] = 1;
8625: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
8626:
8627: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
8628: REG16(AX) = 1;
8629: m_CF = 1;
8630: return;
8631: }
8632: for(char *s = tmp; *s; ++s) {
8633: if(*s == '/') {
8634: *s = '\\';
8635: }
8636: }
8637: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
8638: if(tmp_name) {
8639: ++tmp_name;
8640: } else {
8641: tmp_name = strchr(tmp, ':');
8642: tmp_name = tmp_name ? tmp_name + 1 : tmp;
8643: }
8644:
8645: WIN32_FIND_DATAA fd;
8646: HANDLE fh = FindFirstFileA(tmp, &fd);
8647: if(fh == INVALID_HANDLE_VALUE) {
8648: REG16(AX) = 2;
8649: m_CF = 1;
8650: return;
8651: }
8652: do {
8653: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
8654: strcpy(tmp_name, fd.cFileName);
8655: if(remove(msdos_trimmed_path(tmp, lfn))) {
8656: REG16(AX) = 5;
8657: m_CF = 1;
8658: break;
8659: }
8660: }
8661: } while(FindNextFileA(fh, &fd));
8662: if(!m_CF) {
8663: if(GetLastError() != ERROR_NO_MORE_FILES) {
8664: m_CF = 1;
8665: REG16(AX) = 2;
8666: }
8667: }
8668: FindClose(fh);
8669: }
8670:
1.1 root 8671: inline void msdos_int_21h_714eh()
8672: {
8673: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 8674: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
8675: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8676: WIN32_FIND_DATA fd;
8677:
1.1.1.13 root 8678: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
8679: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8680: FindClose(dtainfo->find_handle);
8681: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8682: }
8683: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 8684: dtainfo->allowable_mask = REG8(CL);
8685: dtainfo->required_mask = REG8(CH);
8686: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 8687:
1.1.1.14 root 8688: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
8689: dtainfo->allowable_mask &= ~8;
1.1 root 8690: }
1.1.1.14 root 8691: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
8692: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 8693: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8694: FindClose(dtainfo->find_handle);
8695: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8696: break;
8697: }
8698: }
8699: }
1.1.1.13 root 8700: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8701: find->attrib = fd.dwFileAttributes;
8702: msdos_find_file_conv_local_time(&fd);
8703: if(REG16(SI) == 0) {
8704: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
8705: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
8706: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
8707: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
8708: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
8709: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
8710: } else {
8711: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
8712: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
8713: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
8714: }
8715: find->size_hi = fd.nFileSizeHigh;
8716: find->size_lo = fd.nFileSizeLow;
8717: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 8718: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 8719: REG16(AX) = dtainfo - dtalist + 1;
8720: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8721: // volume label
8722: find->attrib = 8;
8723: find->size_hi = find->size_lo = 0;
8724: strcpy(find->full_name, process->volume_label);
8725: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 8726: dtainfo->allowable_mask &= ~8;
8727: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 8728: } else {
8729: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 8730: m_CF = 1;
1.1 root 8731: }
8732: }
8733:
8734: inline void msdos_int_21h_714fh()
8735: {
8736: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 8737: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 8738: WIN32_FIND_DATA fd;
8739:
1.1.1.14 root 8740: if(REG16(BX) - 1u >= MAX_DTAINFO) {
8741: REG16(AX) = 6;
1.1.1.13 root 8742: m_CF = 1;
8743: return;
8744: }
1.1.1.14 root 8745: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 8746: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8747: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 8748: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 8749: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8750: FindClose(dtainfo->find_handle);
8751: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8752: break;
8753: }
8754: }
8755: } else {
1.1.1.13 root 8756: FindClose(dtainfo->find_handle);
8757: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8758: }
8759: }
1.1.1.13 root 8760: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8761: find->attrib = fd.dwFileAttributes;
8762: msdos_find_file_conv_local_time(&fd);
8763: if(REG16(SI) == 0) {
8764: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
8765: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
8766: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
8767: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
8768: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
8769: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
8770: } else {
8771: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
8772: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
8773: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
8774: }
8775: find->size_hi = fd.nFileSizeHigh;
8776: find->size_lo = fd.nFileSizeLow;
8777: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 8778: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 8779: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8780: // volume label
8781: find->attrib = 8;
8782: find->size_hi = find->size_lo = 0;
8783: strcpy(find->full_name, process->volume_label);
8784: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 8785: dtainfo->allowable_mask &= ~8;
1.1 root 8786: } else {
8787: REG16(AX) = 0x12;
1.1.1.3 root 8788: m_CF = 1;
1.1 root 8789: }
8790: }
8791:
8792: inline void msdos_int_21h_71a0h()
8793: {
8794: DWORD max_component_len, file_sys_flag;
8795:
1.1.1.14 root 8796: 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))) {
8797: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
8798: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 8799: REG16(CX) = (UINT16)max_component_len; // 255
8800: REG16(DX) = (UINT16)max_component_len + 5; // 260
8801: } else {
8802: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8803: m_CF = 1;
1.1 root 8804: }
8805: }
8806:
8807: inline void msdos_int_21h_71a1h()
8808: {
1.1.1.14 root 8809: if(REG16(BX) - 1u >= MAX_DTAINFO) {
8810: REG16(AX) = 6;
1.1.1.13 root 8811: m_CF = 1;
8812: return;
8813: }
1.1.1.14 root 8814: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 8815: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8816: FindClose(dtainfo->find_handle);
8817: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8818: }
8819: }
8820:
8821: inline void msdos_int_21h_71a6h()
8822: {
8823: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8824: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
8825:
1.1.1.3 root 8826: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8827: struct _stat64 status;
8828: DWORD serial_number = 0;
8829:
1.1.1.20 root 8830: if(fd < process->max_files && file_handler[fd].valid) {
8831: if(_fstat64(fd, &status) == 0) {
8832: if(file_handler[fd].path[1] == ':') {
1.1 root 8833: // NOTE: we need to consider the network file path "\\host\share\"
8834: char volume[] = "A:\\";
1.1.1.20 root 8835: volume[0] = file_handler[fd].path[1];
1.1 root 8836: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
8837: }
1.1.1.20 root 8838: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 8839: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
8840: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
8841: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
8842: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
8843: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
8844: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
8845: *(UINT32 *)(buffer + 0x1c) = serial_number;
8846: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
8847: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
8848: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 8849: // this is dummy id and it will be changed when it is reopened...
1.1 root 8850: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 8851: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 8852: } else {
8853: REG16(AX) = errno;
1.1.1.3 root 8854: m_CF = 1;
1.1 root 8855: }
8856: } else {
8857: REG16(AX) = 0x06;
1.1.1.3 root 8858: m_CF = 1;
1.1 root 8859: }
8860: }
8861:
8862: inline void msdos_int_21h_71a7h()
8863: {
8864: switch(REG8(BL)) {
8865: case 0x00:
1.1.1.3 root 8866: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 8867: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8868: m_CF = 1;
1.1 root 8869: }
8870: break;
8871: case 0x01:
8872: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 8873: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 8874: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8875: m_CF = 1;
1.1 root 8876: }
8877: break;
8878: default:
1.1.1.22 root 8879: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8880: REG16(AX) = 0x01;
1.1.1.3 root 8881: m_CF = 1;
1.1 root 8882: break;
8883: }
8884: }
8885:
8886: inline void msdos_int_21h_71a8h()
8887: {
8888: if(REG8(DH) == 0) {
8889: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 8890: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 8891: memset(fcb, 0x20, sizeof(fcb));
8892: int len = strlen(tmp);
1.1.1.21 root 8893: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 8894: if(tmp[i] == '.') {
8895: pos = 8;
8896: } else {
8897: if(msdos_lead_byte_check(tmp[i])) {
8898: fcb[pos++] = tmp[i++];
8899: }
8900: fcb[pos++] = tmp[i];
8901: }
8902: }
1.1.1.3 root 8903: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 8904: } else {
1.1.1.3 root 8905: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 8906: }
8907: }
8908:
1.1.1.22 root 8909: inline void msdos_int_21h_71aah()
8910: {
8911: char drv[] = "A:", path[MAX_PATH];
8912: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
8913:
8914: if(REG8(BL) == 0) {
8915: drv[0] = 'A' + _getdrive() - 1;
8916: } else {
8917: drv[0] = 'A' + REG8(BL) - 1;
8918: }
8919: switch(REG8(BH)) {
8920: case 0x00:
8921: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
8922: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
8923: if(GetLogicalDrives() & bits) {
8924: REG16(AX) = 0x0f; // invalid drive
8925: } else {
8926: REG16(AX) = 0x03; // path not found
8927: }
8928: m_CF = 1;
8929: }
8930: break;
8931: case 0x01:
8932: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
8933: REG16(AX) = 0x0f; // invalid drive
8934: m_CF = 1;
8935: }
8936: break;
8937: case 0x02:
8938: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
8939: REG16(AX) = 0x0f; // invalid drive
8940: m_CF = 1;
8941: } else if(strncmp(path, "\\??\\", 4) != 0) {
8942: REG16(AX) = 0x0f; // invalid drive
8943: m_CF = 1;
8944: } else {
8945: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
8946: }
8947: break;
8948: default:
8949: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8950: REG16(AX) = 0x01;
8951: m_CF = 1;
8952: break;
8953: }
8954: }
8955:
1.1.1.14 root 8956: inline void msdos_int_21h_7300h()
8957: {
8958: if(REG8(AL) == 0) {
8959: REG8(AL) = REG8(CL);
8960: REG8(AH) = 0;
8961: } else {
8962: REG16(AX) = 0x01;
8963: m_CF = 1;
8964: }
8965: }
8966:
8967: inline void msdos_int_21h_7302h()
8968: {
8969: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
8970: UINT16 seg, ofs;
8971:
8972: if(REG16(CX) < 0x3f) {
8973: REG8(AL) = 0x18;
8974: m_CF = 1;
8975: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8976: REG8(AL) = 0xff;
8977: m_CF = 1;
8978: } else {
8979: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
8980: }
8981: }
8982:
1.1 root 8983: inline void msdos_int_21h_7303h()
8984: {
1.1.1.3 root 8985: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
8986: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 8987: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
8988:
8989: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
8990: info->size_of_structure = sizeof(ext_space_info_t);
8991: info->structure_version = 0;
8992: info->sectors_per_cluster = sectors_per_cluster;
8993: info->bytes_per_sector = bytes_per_sector;
8994: info->available_clusters_on_drive = free_clusters;
8995: info->total_clusters_on_drive = total_clusters;
8996: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
8997: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
8998: info->available_allocation_units = free_clusters; // ???
8999: info->total_allocation_units = total_clusters; // ???
9000: } else {
9001: REG16(AX) = errno;
1.1.1.3 root 9002: m_CF = 1;
1.1 root 9003: }
9004: }
9005:
1.1.1.30 root 9006: inline void msdos_int_21h_dbh()
9007: {
9008: // Novell NetWare - Workstation - Get Number of Local Drives
9009: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
9010: REG8(AL) = dos_info->last_drive;
9011: }
9012:
9013: inline void msdos_int_21h_dch()
9014: {
9015: // Novell NetWare - Connection Services - Get Connection Number
9016: REG8(AL) = 0x00;
9017: }
9018:
1.1.1.32! root 9019: inline void msdos_int_24h()
! 9020: {
! 9021: const char *message = NULL;
! 9022: int key = 0;
! 9023:
! 9024: for(int i = 0; i < array_length(critical_error_table); i++) {
! 9025: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
! 9026: if(active_code_page == 932) {
! 9027: message = critical_error_table[i].message_japanese;
! 9028: }
! 9029: if(message == NULL) {
! 9030: message = critical_error_table[i].message_english;
! 9031: }
! 9032: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
! 9033: strcpy((char *)(mem + WORK_TOP + 1), message);
! 9034:
! 9035: SREG(ES) = WORK_TOP >> 4;
! 9036: i386_load_segment_descriptor(ES);
! 9037: REG16(DI) = 0x0000;
! 9038: break;
! 9039: }
! 9040: }
! 9041: fprintf(stderr, "\n%s", message);
! 9042: if(!(REG8(AH) & 0x80)) {
! 9043: if(REG8(AH) & 0x01) {
! 9044: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
! 9045: } else {
! 9046: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
! 9047: }
! 9048: }
! 9049: fprintf(stderr, "\n");
! 9050:
! 9051: // if(1) {
! 9052: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
! 9053: // }
! 9054: if(REG8(AH) & 0x10) {
! 9055: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
! 9056: }
! 9057: if(REG8(AH) & 0x20) {
! 9058: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
! 9059: }
! 9060: if(REG8(AH) & 0x08) {
! 9061: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
! 9062: }
! 9063: fprintf(stderr, "? ");
! 9064:
! 9065: while(1) {
! 9066: while(!_kbhit()) {
! 9067: Sleep(10);
! 9068: }
! 9069: key = _getch();
! 9070:
! 9071: if(key == 'I' || key == 'i') {
! 9072: if(REG8(AH) & 0x20) {
! 9073: REG8(AL) = 0;
! 9074: break;
! 9075: }
! 9076: } else if(key == 'R' || key == 'r') {
! 9077: if(REG8(AH) & 0x10) {
! 9078: REG8(AL) = 1;
! 9079: break;
! 9080: }
! 9081: } else if(key == 'A' || key == 'a') {
! 9082: REG8(AL) = 2;
! 9083: break;
! 9084: } else if(key == 'F' || key == 'f') {
! 9085: if(REG8(AH) & 0x08) {
! 9086: REG8(AL) = 3;
! 9087: break;
! 9088: }
! 9089: }
! 9090: }
! 9091: fprintf(stderr, "%c\n", key);
! 9092: }
! 9093:
1.1 root 9094: inline void msdos_int_25h()
9095: {
9096: UINT16 seg, ofs;
9097: DWORD dwSize;
9098:
1.1.1.3 root 9099: #if defined(HAS_I386)
9100: I386OP(pushf)();
9101: #else
9102: PREFIX86(_pushf());
9103: #endif
1.1 root 9104:
9105: if(!(REG8(AL) < 26)) {
9106: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 9107: m_CF = 1;
1.1 root 9108: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
9109: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 9110: m_CF = 1;
1.1 root 9111: } else {
9112: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9113: char dev[64];
9114: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
9115:
9116: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
9117: if(hFile == INVALID_HANDLE_VALUE) {
9118: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 9119: m_CF = 1;
1.1 root 9120: } else {
1.1.1.19 root 9121: UINT32 top_sector = REG16(DX);
9122: UINT16 sector_num = REG16(CX);
9123: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
9124:
9125: if(sector_num == 0xffff) {
9126: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
9127: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
9128: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
9129: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
9130: buffer_addr = (seg << 4) + ofs;
9131: }
9132: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
9133: // REG8(AL) = 0x02; // drive not ready
9134: // m_CF = 1;
9135: // } else
9136: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 9137: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 9138: m_CF = 1;
1.1.1.19 root 9139: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 9140: REG8(AL) = 0x0b; // read error
1.1.1.3 root 9141: m_CF = 1;
1.1 root 9142: }
9143: CloseHandle(hFile);
9144: }
9145: }
9146: }
9147:
9148: inline void msdos_int_26h()
9149: {
9150: // this operation may cause serious damage for drives, so always returns error...
9151: UINT16 seg, ofs;
9152: DWORD dwSize;
9153:
1.1.1.3 root 9154: #if defined(HAS_I386)
9155: I386OP(pushf)();
9156: #else
9157: PREFIX86(_pushf());
9158: #endif
1.1 root 9159:
9160: if(!(REG8(AL) < 26)) {
9161: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 9162: m_CF = 1;
1.1 root 9163: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
9164: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 9165: m_CF = 1;
1.1 root 9166: } else {
9167: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9168: char dev[64];
9169: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
9170:
9171: if(dpb->media_type == 0xf8) {
9172: // this drive is not a floppy
1.1.1.6 root 9173: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
9174: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
9175: // }
1.1 root 9176: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 9177: m_CF = 1;
1.1 root 9178: } else {
9179: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
9180: if(hFile == INVALID_HANDLE_VALUE) {
9181: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 9182: m_CF = 1;
1.1 root 9183: } else {
1.1.1.19 root 9184: UINT32 top_sector = REG16(DX);
9185: UINT16 sector_num = REG16(CX);
9186: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
9187:
9188: if(sector_num == 0xffff) {
9189: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
9190: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
9191: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
9192: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
9193: buffer_addr = (seg << 4) + ofs;
9194: }
1.1 root 9195: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
9196: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 9197: m_CF = 1;
1.1.1.19 root 9198: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 9199: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 9200: m_CF = 1;
1.1.1.19 root 9201: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 9202: REG8(AL) = 0x0a; // write error
1.1.1.3 root 9203: m_CF = 1;
1.1 root 9204: }
9205: CloseHandle(hFile);
9206: }
9207: }
9208: }
9209: }
9210:
9211: inline void msdos_int_27h()
9212: {
1.1.1.29 root 9213: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
9214: try {
9215: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
9216: } catch(...) {
9217: // recover the broken mcb
9218: int mcb_seg = SREG(CS) - 1;
9219: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9220: if(mcb_seg < (MEMORY_END >> 4)) {
9221: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
9222: mcb->mz = 'M';
9223: } else {
9224: mcb->mz = 'Z';
9225: }
1.1.1.30 root 9226: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
1.1.1.29 root 9227: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
9228: } else {
9229: mcb->mz = 'Z';
1.1.1.30 root 9230: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 9231: }
9232: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
9233: }
1.1.1.3 root 9234: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 9235: }
9236:
9237: inline void msdos_int_29h()
9238: {
1.1.1.14 root 9239: #if 1
9240: // need to check escape sequences
1.1 root 9241: msdos_putch(REG8(AL));
1.1.1.14 root 9242: #else
9243: DWORD num;
9244: vram_flush();
1.1.1.23 root 9245: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 9246: cursor_moved = true;
9247: #endif
1.1 root 9248: }
9249:
9250: inline void msdos_int_2eh()
9251: {
9252: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
9253: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 9254: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 9255: char *token = my_strtok(tmp, " ");
9256: strcpy(command, token);
9257: strcpy(opt, token + strlen(token) + 1);
9258:
9259: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
9260: param->env_seg = 0;
9261: param->cmd_line.w.l = 44;
9262: param->cmd_line.w.h = (WORK_TOP >> 4);
9263: param->fcb1.w.l = 24;
9264: param->fcb1.w.h = (WORK_TOP >> 4);
9265: param->fcb2.w.l = 24;
9266: param->fcb2.w.h = (WORK_TOP >> 4);
9267:
9268: memset(mem + WORK_TOP + 24, 0x20, 20);
9269:
9270: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
9271: cmd_line->len = strlen(opt);
9272: strcpy(cmd_line->cmd, opt);
9273: cmd_line->cmd[cmd_line->len] = 0x0d;
9274:
1.1.1.28 root 9275: try {
9276: if(msdos_process_exec(command, param, 0)) {
9277: REG16(AX) = 0xffff; // error before processing command
9278: } else {
9279: // set flag to set retval to ax when the started process is terminated
9280: process_t *process = msdos_process_info_get(current_psp);
9281: process->called_by_int2eh = true;
9282: }
9283: } catch(...) {
9284: REG16(AX) = 0xffff; // error before processing command
9285: }
1.1 root 9286: }
9287:
1.1.1.29 root 9288: inline void msdos_int_2fh_05h()
9289: {
9290: switch(REG8(AL)) {
9291: case 0x00:
1.1.1.32! root 9292: REG8(AL) = 0xff;
! 9293: break;
! 9294: case 0x01:
! 9295: case 0x02:
! 9296: for(int i = 0; i < array_length(standard_error_table); i++) {
! 9297: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
! 9298: const char *message = NULL;
! 9299: if(active_code_page == 932) {
! 9300: message = standard_error_table[i].message_japanese;
! 9301: }
! 9302: if(message == NULL) {
! 9303: message = standard_error_table[i].message_english;
! 9304: }
! 9305: strcpy((char *)(mem + WORK_TOP), message);
! 9306:
! 9307: SREG(ES) = WORK_TOP >> 4;
! 9308: i386_load_segment_descriptor(ES);
! 9309: REG16(DI) = 0x0000;
! 9310: REG8(AL) = 0x01;
! 9311: break;
! 9312: }
! 9313: }
1.1.1.29 root 9314: break;
9315: default:
9316: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9317: m_CF = 1;
9318: }
9319: }
9320:
1.1.1.22 root 9321: inline void msdos_int_2fh_11h()
9322: {
9323: switch(REG8(AL)) {
9324: case 0x00:
1.1.1.29 root 9325: if(i386_read_stack() == 0xdada) {
9326: // MSCDEX is not installed
9327: // REG8(AL) = 0x00;
9328: } else {
9329: // Network Redirector is not installed
9330: // REG8(AL) = 0x00;
9331: }
1.1.1.22 root 9332: break;
9333: default:
9334: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.29 root 9335: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 9336: m_CF = 1;
9337: break;
9338: }
9339: }
9340:
1.1.1.21 root 9341: inline void msdos_int_2fh_12h()
9342: {
9343: switch(REG8(AL)) {
1.1.1.22 root 9344: case 0x00:
1.1.1.29 root 9345: // DOS 3.0+ internal functions are installed
1.1.1.22 root 9346: REG8(AL) = 0xff;
9347: break;
1.1.1.29 root 9348: // case 0x01: // DOS 3.0+ internal - Close Current File
9349: case 0x02:
9350: {
9351: UINT16 stack = i386_read_stack();
9352: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
9353: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
9354: i386_load_segment_descriptor(ES);
9355: }
9356: break;
1.1.1.30 root 9357: case 0x03:
9358: SREG(DS) = (DEVICE_TOP >> 4);
9359: i386_load_segment_descriptor(DS);
9360: break;
1.1.1.29 root 9361: case 0x04:
9362: {
9363: UINT16 stack = i386_read_stack();
9364: REG8(AL) = (stack == '/') ? '\\' : stack;
9365: #if defined(HAS_I386)
9366: m_ZF = (REG8(AL) == '\\');
9367: #else
9368: m_ZeroVal = (REG8(AL) != '\\');
9369: #endif
9370: }
9371: break;
9372: case 0x05:
9373: msdos_putch(i386_read_stack());
9374: break;
9375: // case 0x06: // DOS 3.0+ internal - Invole Critical Error
9376: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
9377: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
9378: // case 0x09: // DOS 3.0+ internal - Flush and FREE Disk Buffer
9379: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
9380: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
9381: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
9382: case 0x0d:
9383: {
9384: SYSTEMTIME time;
9385: FILETIME file_time;
9386: WORD dos_date, dos_time;
9387: GetLocalTime(&time);
9388: SystemTimeToFileTime(&time, &file_time);
9389: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
9390: REG16(AX) = dos_date;
9391: REG16(DX) = dos_time;
9392: }
9393: break;
9394: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
9395: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
9396: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
9397: case 0x11:
9398: {
9399: char path[MAX_PATH], *p;
9400: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
9401: my_strupr(path);
9402: while((p = my_strchr(path, '/')) != NULL) {
9403: *p = '\\';
9404: }
9405: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
9406: }
9407: break;
9408: case 0x12:
9409: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
9410: break;
9411: case 0x13:
9412: {
9413: char tmp[2] = {0};
9414: tmp[0] = i386_read_stack();
9415: my_strupr(tmp);
9416: REG8(AL) = tmp[0];
9417: }
9418: break;
9419: case 0x14:
9420: #if defined(HAS_I386)
9421: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
9422: #else
9423: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
9424: #endif
9425: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
9426: break;
9427: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 9428: case 0x16:
9429: if(REG16(BX) < 20) {
9430: SREG(ES) = SFT_TOP >> 4;
9431: i386_load_segment_descriptor(ES);
9432: REG16(DI) = 6 + 0x3b * REG16(BX);
9433:
9434: // update system file table
9435: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
9436: if(file_handler[REG16(BX)].valid) {
9437: int count = 0;
9438: for(int i = 0; i < 20; i++) {
9439: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
9440: count++;
9441: }
9442: }
9443: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
9444: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
9445: _lseek(REG16(BX), 0, SEEK_END);
9446: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
9447: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
9448: } else {
9449: memset(sft, 0, 0x3b);
9450: }
9451: } else {
9452: REG16(AX) = 0x06;
9453: m_CF = 1;
9454: }
9455: break;
1.1.1.29 root 9456: // case 0x17: // DOS 3.0+ internal - Get Current Directory Structure for Drive
9457: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
9458: // case 0x19: // DOS 3.0+ internal - Set Drive???
9459: case 0x1a:
9460: {
9461: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
9462: if(path[1] == ':') {
9463: if(path[0] >= 'a' && path[0] <= 'z') {
9464: REG8(AL) = path[0] - 'a' + 1;
9465: } else if(path[0] >= 'A' && path[0] <= 'Z') {
9466: REG8(AL) = path[0] - 'A' + 1;
9467: } else {
9468: REG8(AL) = 0xff; // invalid
9469: }
9470: strcpy(full, path);
9471: strcpy(path, full + 2);
9472: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
9473: if(full[0] >= 'a' && full[0] <= 'z') {
9474: REG8(AL) = full[0] - 'a' + 1;
9475: } else if(full[0] >= 'A' && full[0] <= 'Z') {
9476: REG8(AL) = full[0] - 'A' + 1;
9477: } else {
9478: REG8(AL) = 0xff; // invalid
9479: }
9480: } else {
9481: REG8(AL) = 0x00; // default
9482: }
9483: }
9484: break;
9485: case 0x1b:
9486: {
9487: int year = REG16(CX) + 1980;
9488: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
9489: }
9490: break;
9491: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
9492: // case 0x1d: // DOS 3.0+ internal - Sum Memory
9493: case 0x1e:
9494: {
9495: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
9496: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
9497: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
9498: #if defined(HAS_I386)
9499: m_ZF = (strcmp(full_1st, full_2nd) == 0);
9500: #else
9501: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
9502: #endif
9503: } else {
9504: #if defined(HAS_I386)
9505: m_ZF = (strcmp(path_1st, path_2nd) == 0);
9506: #else
9507: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
9508: #endif
9509: }
9510: }
9511: break;
9512: // case 0x1f: // DOS 3.0+ internal - Build Current Directory Structure
1.1.1.21 root 9513: case 0x20:
9514: {
9515: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9516:
9517: if(fd < 20) {
9518: SREG(ES) = current_psp;
9519: i386_load_segment_descriptor(ES);
9520: REG16(DI) = offsetof(psp_t, file_table) + fd;
9521: } else {
9522: REG16(AX) = 0x06;
9523: m_CF = 1;
9524: }
9525: }
9526: break;
1.1.1.29 root 9527: case 0x21:
9528: msdos_int_21h_60h(0);
9529: break;
9530: // case 0x22: // DOS 3.0+ internal - Set Extended Error Info
9531: // case 0x23: // DOS 3.0+ internal - Check If Character Device
9532: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
9533: case 0x25:
9534: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
9535: break;
9536: case 0x26:
9537: REG8(AL) = REG8(CL);
9538: msdos_int_21h_3dh();
9539: break;
9540: case 0x27:
9541: msdos_int_21h_3eh();
9542: break;
9543: case 0x28:
9544: REG16(AX) = REG16(BP);
9545: msdos_int_21h_42h();
9546: break;
9547: case 0x29:
9548: msdos_int_21h_3fh();
9549: break;
9550: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
9551: case 0x2b:
9552: REG16(AX) = REG16(BP);
9553: msdos_int_21h_44h();
9554: break;
9555: case 0x2c:
9556: REG16(BX) = DEVICE_TOP >> 4;
9557: REG16(AX) = 22;
9558: break;
9559: case 0x2d:
9560: {
9561: sda_t *sda = (sda_t *)(mem + SDA_TOP);
9562: REG16(AX) = sda->extended_error_code;
9563: }
9564: break;
9565: case 0x2e:
9566: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32! root 9567: SREG(ES) = 0x0001;
! 9568: i386_load_segment_descriptor(ES);
! 9569: REG16(DI) = 0x00;
! 9570: } else if(REG8(DL) == 0x08) {
! 9571: // dummy parameter error message read routine is at fffd:0010
! 9572: SREG(ES) = 0xfffd;
1.1.1.22 root 9573: i386_load_segment_descriptor(ES);
1.1.1.32! root 9574: REG16(DI) = 0x0010;
1.1.1.22 root 9575: }
9576: break;
1.1.1.29 root 9577: case 0x2f:
9578: if(REG16(DX) != 0) {
1.1.1.30 root 9579: dos_major_version = REG8(DL);
9580: dos_minor_version = REG8(DH);
1.1.1.29 root 9581: } else {
9582: REG8(DL) = 7;
9583: REG8(DH) = 10;
9584: }
9585: break;
9586: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
9587: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 9588: default:
9589: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9590: REG16(AX) = 0x01;
9591: m_CF = 1;
9592: break;
9593: }
9594: }
9595:
1.1.1.30 root 9596: inline void msdos_int_2fh_13h()
9597: {
9598: static UINT16 prevDS = 0, prevDX = 0;
9599: static UINT16 prevES = 0, prevBX = 0;
9600: UINT16 tmp;
9601:
9602: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
9603: i386_load_segment_descriptor(DS);
9604: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
9605:
9606: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
9607: i386_load_segment_descriptor(ES);
9608: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
9609: }
9610:
1.1.1.22 root 9611: inline void msdos_int_2fh_14h()
9612: {
9613: switch(REG8(AL)) {
9614: case 0x00:
1.1.1.29 root 9615: // NLSFUNC.COM is installed
9616: REG8(AL) = 0xff;
1.1.1.25 root 9617: break;
9618: case 0x01:
9619: case 0x03:
9620: REG8(AL) = 0x00;
9621: active_code_page = REG16(BX);
9622: msdos_nls_tables_update();
9623: break;
9624: case 0x02:
9625: REG8(AL) = get_extended_country_info(REG16(BP));
9626: break;
9627: case 0x04:
9628: REG8(AL) = 0x00;
9629: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 9630: break;
9631: default:
9632: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9633: REG16(AX) = 0x01;
9634: m_CF = 1;
9635: break;
9636: }
9637: }
9638:
9639: inline void msdos_int_2fh_15h()
9640: {
9641: switch(REG8(AL)) {
1.1.1.29 root 9642: case 0x00: // CD-ROM - Installation Check
9643: if(REG16(BX) == 0x0000) {
9644: // MSCDEX is not installed
9645: // REG8(AL) = 0x00;
9646: } else {
9647: // GRAPHICS.COM is not installed
9648: // REG8(AL) = 0x00;
9649: }
1.1.1.22 root 9650: break;
9651: case 0xff:
1.1.1.29 root 9652: if(REG16(BX) == 0x0000) {
9653: // CORELCDX is not installed
9654: } else {
9655: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9656: REG16(AX) = 0x01;
9657: m_CF = 1;
9658: }
1.1.1.22 root 9659: break;
1.1.1.21 root 9660: default:
1.1.1.22 root 9661: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.21 root 9662: REG16(AX) = 0x01;
9663: m_CF = 1;
9664: break;
9665: }
9666: }
9667:
1.1 root 9668: inline void msdos_int_2fh_16h()
9669: {
9670: switch(REG8(AL)) {
9671: case 0x00:
1.1.1.14 root 9672: if(no_windows) {
1.1.1.29 root 9673: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
9674: // REG8(AL) = 0x00;
1.1.1.14 root 9675: } else {
1.1.1.30 root 9676: REG8(AL) = win_major_version;
9677: REG8(AH) = win_minor_version;
1.1 root 9678: }
9679: break;
1.1.1.30 root 9680: case 0x05:
9681: // from DOSBox
9682: i386_set_a20_line(1);
9683: break;
1.1.1.22 root 9684: case 0x0a:
9685: if(!no_windows) {
9686: REG16(AX) = 0x0000;
1.1.1.30 root 9687: REG8(BH) = win_major_version;
9688: REG8(BL) = win_minor_version;
1.1.1.22 root 9689: REG16(CX) = 0x0003; // enhanced
9690: }
9691: break;
1.1.1.30 root 9692: case 0x0b:
9693: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 9694: case 0x0e:
9695: case 0x0f:
1.1.1.30 root 9696: case 0x10:
1.1.1.22 root 9697: case 0x11:
9698: case 0x12:
9699: case 0x13:
9700: case 0x14:
1.1.1.30 root 9701: case 0x15:
1.1.1.22 root 9702: case 0x87:
1.1.1.30 root 9703: case 0x89:
1.1.1.22 root 9704: // function not supported, do not clear AX
9705: break;
1.1.1.14 root 9706: case 0x80:
9707: Sleep(10);
9708: hardware_update();
1.1.1.29 root 9709: REG8(AL) = 0x00;
1.1.1.14 root 9710: break;
1.1.1.22 root 9711: case 0x8e:
9712: REG16(AX) = 0x00; // failed
9713: break;
1.1.1.20 root 9714: case 0x8f:
9715: switch(REG8(DH)) {
9716: case 0x00:
9717: case 0x02:
9718: case 0x03:
9719: REG16(AX) = 0x00;
9720: break;
9721: case 0x01:
9722: REG16(AX) = 0x168f;
9723: break;
9724: }
9725: break;
1.1 root 9726: default:
1.1.1.22 root 9727: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9728: REG16(AX) = 0x01;
9729: m_CF = 1;
9730: break;
9731: }
9732: }
9733:
9734: inline void msdos_int_2fh_19h()
9735: {
9736: switch(REG8(AL)) {
9737: case 0x00:
1.1.1.29 root 9738: // SHELLB.COM is not installed
9739: // REG8(AL) = 0x00;
1.1.1.22 root 9740: break;
9741: case 0x01:
9742: case 0x02:
9743: case 0x03:
9744: case 0x04:
9745: REG16(AX) = 0x01;
9746: m_CF = 1;
9747: break;
1.1.1.29 root 9748: case 0x80:
9749: // IBM ROM-DOS v4.0 is not installed
9750: // REG8(AL) = 0x00;
9751: break;
1.1.1.22 root 9752: default:
9753: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 9754: REG16(AX) = 0x01;
1.1.1.3 root 9755: m_CF = 1;
1.1 root 9756: break;
9757: }
9758: }
9759:
9760: inline void msdos_int_2fh_1ah()
9761: {
9762: switch(REG8(AL)) {
9763: case 0x00:
1.1.1.29 root 9764: // ANSI.SYS is installed
1.1 root 9765: REG8(AL) = 0xff;
9766: break;
9767: default:
1.1.1.22 root 9768: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9769: REG16(AX) = 0x01;
9770: m_CF = 1;
9771: break;
9772: }
9773: }
9774:
1.1.1.30 root 9775: inline void msdos_int_2fh_40h()
1.1.1.22 root 9776: {
9777: switch(REG8(AL)) {
9778: case 0x00:
1.1.1.30 root 9779: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
9780: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 9781: break;
9782: default:
9783: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 9784: REG16(AX) = 0x01;
1.1.1.3 root 9785: m_CF = 1;
1.1 root 9786: break;
9787: }
9788: }
9789:
9790: inline void msdos_int_2fh_43h()
9791: {
9792: switch(REG8(AL)) {
9793: case 0x00:
1.1.1.29 root 9794: // XMS is installed ?
1.1.1.19 root 9795: #ifdef SUPPORT_XMS
9796: if(support_xms) {
9797: REG8(AL) = 0x80;
9798: } else
9799: #endif
9800: REG8(AL) = 0x00;
9801: break;
9802: case 0x10:
9803: SREG(ES) = XMS_TOP >> 4;
9804: i386_load_segment_descriptor(ES);
1.1.1.26 root 9805: REG16(BX) = 0x15;
1.1 root 9806: break;
9807: default:
1.1.1.22 root 9808: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9809: REG16(AX) = 0x01;
9810: m_CF = 1;
9811: break;
9812: }
9813: }
9814:
9815: inline void msdos_int_2fh_46h()
9816: {
9817: switch(REG8(AL)) {
9818: case 0x80:
1.1.1.29 root 9819: // Windows v3.0 is not installed
9820: // REG8(AL) = 0x00;
1.1.1.22 root 9821: break;
9822: default:
9823: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9824: REG16(AX) = 0x01;
9825: m_CF = 1;
9826: break;
9827: }
9828: }
9829:
9830: inline void msdos_int_2fh_48h()
9831: {
9832: switch(REG8(AL)) {
9833: case 0x00:
1.1.1.29 root 9834: // DOSKEY is not installed
9835: // REG8(AL) = 0x00;
1.1.1.22 root 9836: break;
9837: case 0x10:
9838: msdos_int_21h_0ah();
9839: REG16(AX) = 0x00;
9840: break;
9841: default:
9842: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 9843: REG16(AX) = 0x01;
1.1.1.3 root 9844: m_CF = 1;
1.1 root 9845: break;
9846: }
9847: }
9848:
9849: inline void msdos_int_2fh_4ah()
9850: {
9851: switch(REG8(AL)) {
1.1.1.29 root 9852: #ifdef SUPPORT_HMA
9853: case 0x01: // DOS 5.0+ - Query Free HMA Space
9854: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
9855: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
9856: // restore first free mcb in high memory area
9857: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
9858: }
9859: int offset = 0xffff;
9860: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
9861: REG16(DI) = offset + 0x10;
9862: } else {
9863: REG16(DI) = 0xffff;
9864: }
9865: } else {
9866: // HMA is already used
9867: REG16(BX) = 0;
9868: REG16(DI) = 0xffff;
9869: }
9870: SREG(ES) = 0xffff;
9871: i386_load_segment_descriptor(ES);
9872: break;
9873: case 0x02: // DOS 5.0+ - Allocate HMA Space
9874: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
9875: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
9876: // restore first free mcb in high memory area
9877: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
9878: }
9879: int size = REG16(BX), offset;
9880: if((size % 16) != 0) {
9881: size &= ~15;
9882: size += 16;
9883: }
9884: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
9885: REG16(BX) = size;
9886: REG16(DI) = offset + 0x10;
9887: is_hma_used_by_int_2fh = true;
9888: } else {
9889: REG16(BX) = 0;
9890: REG16(DI) = 0xffff;
9891: }
9892: } else {
9893: // HMA is already used
9894: REG16(BX) = 0;
9895: REG16(DI) = 0xffff;
9896: }
9897: SREG(ES) = 0xffff;
9898: i386_load_segment_descriptor(ES);
9899: break;
9900: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
9901: if(REG8(DL) == 0x00) {
9902: if(!is_hma_used_by_xms) {
9903: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
9904: // restore first free mcb in high memory area
9905: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
9906: is_hma_used_by_int_2fh = false;
9907: }
9908: int size = REG16(BX), offset;
9909: if((size % 16) != 0) {
9910: size &= ~15;
9911: size += 16;
9912: }
9913: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
9914: // REG16(BX) = size;
9915: SREG(ES) = 0xffff;
9916: i386_load_segment_descriptor(ES);
9917: REG16(DI) = offset + 0x10;
9918: is_hma_used_by_int_2fh = true;
9919: } else {
9920: REG16(DI) = 0xffff;
9921: }
9922: } else {
9923: REG16(DI) = 0xffff;
9924: }
9925: } else if(REG8(DL) == 0x01) {
9926: if(!is_hma_used_by_xms) {
9927: int size = REG16(BX);
9928: if((size % 16) != 0) {
9929: size &= ~15;
9930: size += 16;
9931: }
9932: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
9933: // memory block address is not changed
9934: } else {
9935: REG16(DI) = 0xffff;
9936: }
9937: } else {
9938: REG16(DI) = 0xffff;
9939: }
9940: } else if(REG8(DL) == 0x02) {
9941: if(!is_hma_used_by_xms) {
9942: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
9943: // restore first free mcb in high memory area
9944: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
9945: is_hma_used_by_int_2fh = false;
9946: } else {
9947: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
9948: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
9949: is_hma_used_by_int_2fh = false;
9950: }
9951: }
9952: }
9953: } else {
9954: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9955: REG16(AX) = 0x01;
9956: m_CF = 1;
9957: }
9958: break;
9959: case 0x04: // Windows95 - Get Start of HMA Memory Chain
9960: if(!is_hma_used_by_xms) {
9961: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
9962: // restore first free mcb in high memory area
9963: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
9964: is_hma_used_by_int_2fh = false;
9965: }
9966: REG16(AX) = 0x0000;
9967: SREG(ES) = 0xffff;
9968: i386_load_segment_descriptor(ES);
9969: REG16(DI) = 0x10;
9970: }
9971: break;
9972: #else
1.1 root 9973: case 0x01:
9974: case 0x02:
1.1.1.29 root 9975: // HMA is already used
1.1.1.27 root 9976: REG16(BX) = 0x0000;
1.1.1.3 root 9977: SREG(ES) = 0xffff;
9978: i386_load_segment_descriptor(ES);
1.1 root 9979: REG16(DI) = 0xffff;
9980: break;
1.1.1.19 root 9981: case 0x03:
9982: // unable to allocate
9983: REG16(DI) = 0xffff;
9984: break;
9985: case 0x04:
9986: // function not supported, do not clear AX
9987: break;
1.1.1.29 root 9988: #endif
9989: case 0x10:
9990: if(REG16(BX) == 0x0000) {
9991: // SMARTDRV is not installed
9992: } else {
9993: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9994: REG16(AX) = 0x01;
9995: m_CF = 1;
9996: }
9997: break;
9998: case 0x11:
9999: if(REG16(BX) == 0x0000) {
10000: // DBLSPACE.BIN is not installed
10001: } else {
10002: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10003: REG16(AX) = 0x01;
10004: m_CF = 1;
10005: }
1.1.1.22 root 10006: break;
10007: default:
10008: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10009: REG16(AX) = 0x01;
10010: m_CF = 1;
10011: break;
10012: }
10013: }
10014:
10015: inline void msdos_int_2fh_4bh()
10016: {
10017: switch(REG8(AL)) {
1.1.1.24 root 10018: case 0x01:
1.1.1.22 root 10019: case 0x02:
1.1.1.29 root 10020: // Task Switcher is not installed
1.1.1.24 root 10021: break;
10022: case 0x03:
10023: // this call is available from within DOSSHELL even if the task switcher is not installed
10024: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 10025: break;
1.1.1.30 root 10026: case 0x04:
10027: REG16(BX) = 0x0000; // free switcher id successfully
10028: break;
1.1 root 10029: default:
1.1.1.22 root 10030: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10031: REG16(AX) = 0x01;
1.1.1.3 root 10032: m_CF = 1;
1.1 root 10033: break;
10034: }
10035: }
10036:
10037: inline void msdos_int_2fh_4fh()
10038: {
10039: switch(REG8(AL)) {
10040: case 0x00:
1.1.1.29 root 10041: // BILING is installed
1.1.1.27 root 10042: REG16(AX) = 0x0000;
10043: REG8(DL) = 0x01; // major version
10044: REG8(DH) = 0x00; // minor version
1.1 root 10045: break;
10046: case 0x01:
1.1.1.27 root 10047: REG16(AX) = 0x0000;
1.1 root 10048: REG16(BX) = active_code_page;
10049: break;
10050: default:
1.1.1.22 root 10051: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10052: REG16(AX) = 0x01;
10053: m_CF = 1;
10054: break;
10055: }
10056: }
10057:
10058: inline void msdos_int_2fh_55h()
10059: {
10060: switch(REG8(AL)) {
10061: case 0x00:
10062: case 0x01:
10063: // unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10064: break;
10065: default:
10066: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10067: REG16(AX) = 0x01;
1.1.1.3 root 10068: m_CF = 1;
1.1 root 10069: break;
10070: }
10071: }
10072:
1.1.1.30 root 10073: inline void msdos_int_2fh_80h()
1.1.1.29 root 10074: {
10075: switch(REG8(AL)) {
10076: case 0x00:
1.1.1.30 root 10077: if(REG16(DX) == 0x0000) {
10078: // FAX BIOS is not installed
10079: // REG8(AL) = 0x00;
10080: } else {
10081: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10082: REG16(AX) = 0x01;
10083: m_CF = 1;
10084: }
1.1.1.29 root 10085: break;
10086: default:
10087: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10088: REG16(AX) = 0x01;
10089: m_CF = 1;
10090: break;
10091: }
10092: }
10093:
1.1.1.24 root 10094: inline void msdos_int_2fh_adh()
10095: {
10096: switch(REG8(AL)) {
10097: case 0x00:
1.1.1.29 root 10098: // DISPLAY.SYS is installed
1.1.1.24 root 10099: REG8(AL) = 0xff;
10100: REG16(BX) = 0x100; // ???
10101: break;
10102: case 0x01:
10103: active_code_page = REG16(BX);
10104: msdos_nls_tables_update();
10105: REG16(AX) = 0x01;
10106: break;
10107: case 0x02:
10108: REG16(BX) = active_code_page;
10109: break;
10110: case 0x03:
10111: // FIXME
10112: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
10113: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
10114: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
10115: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
10116: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
10117: break;
10118: case 0x80:
10119: break; // keyb.com is not installed
10120: default:
10121: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10122: REG16(AX) = 0x01;
10123: m_CF = 1;
10124: break;
10125: }
10126: }
10127:
1.1 root 10128: inline void msdos_int_2fh_aeh()
10129: {
10130: switch(REG8(AL)) {
10131: case 0x00:
1.1.1.28 root 10132: // FIXME: we need to check the given command line
10133: REG8(AL) = 0x00; // the command should be executed as usual
10134: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 10135: break;
10136: case 0x01:
10137: {
10138: char command[MAX_PATH];
10139: memset(command, 0, sizeof(command));
1.1.1.3 root 10140: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 10141:
10142: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
10143: param->env_seg = 0;
10144: param->cmd_line.w.l = 44;
10145: param->cmd_line.w.h = (WORK_TOP >> 4);
10146: param->fcb1.w.l = 24;
10147: param->fcb1.w.h = (WORK_TOP >> 4);
10148: param->fcb2.w.l = 24;
10149: param->fcb2.w.h = (WORK_TOP >> 4);
10150:
10151: memset(mem + WORK_TOP + 24, 0x20, 20);
10152:
10153: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 10154: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
10155: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 10156: cmd_line->cmd[cmd_line->len] = 0x0d;
10157:
1.1.1.28 root 10158: try {
10159: msdos_process_exec(command, param, 0);
10160: } catch(...) {
10161: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 10162: }
10163: }
10164: break;
10165: default:
1.1.1.22 root 10166: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10167: REG16(AX) = 0x01;
1.1.1.3 root 10168: m_CF = 1;
1.1 root 10169: break;
10170: }
10171: }
10172:
10173: inline void msdos_int_2fh_b7h()
10174: {
10175: switch(REG8(AL)) {
10176: case 0x00:
1.1.1.30 root 10177: // APPEND is not installed
1.1.1.29 root 10178: // REG8(AL) = 0x00;
1.1 root 10179: break;
1.1.1.22 root 10180: case 0x07:
10181: case 0x11:
10182: break;
1.1 root 10183: default:
1.1.1.22 root 10184: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10185: REG16(AX) = 0x01;
1.1.1.3 root 10186: m_CF = 1;
1.1 root 10187: break;
10188: }
10189: }
10190:
1.1.1.30 root 10191: inline void msdos_int_2fh_d7h()
1.1.1.29 root 10192: {
10193: switch(REG8(AL)) {
1.1.1.30 root 10194: case 0x01:
10195: // Banyan VINES v4+ is not installed
1.1.1.29 root 10196: break;
10197: default:
10198: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10199: REG16(AX) = 0x01;
10200: m_CF = 1;
10201: break;
10202: }
10203: }
10204:
1.1.1.24 root 10205: inline void msdos_int_33h_0000h()
10206: {
10207: REG16(AX) = 0xffff; // hardware/driver installed
10208: REG16(BX) = MAX_MOUSE_BUTTONS;
10209: }
10210:
10211: inline void msdos_int_33h_0001h()
10212: {
10213: if(!mouse.active) {
10214: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
10215: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
10216: }
10217: mouse.active = true;
10218: pic[1].imr &= ~0x10; // enable irq12
10219: }
10220: }
10221:
10222: inline void msdos_int_33h_0002h()
10223: {
10224: if(mouse.active) {
10225: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
10226: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
10227: }
10228: mouse.active = false;
10229: pic[1].imr |= 0x10; // disable irq12
10230: }
10231: }
10232:
10233: inline void msdos_int_33h_0003h()
10234: {
10235: REG16(BX) = mouse.get_buttons();
10236: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
10237: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
10238: }
10239:
10240: inline void msdos_int_33h_0005h()
10241: {
10242: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
10243: int idx = REG16(BX);
10244: REG16(BX) = mouse.buttons[idx].pressed_times;
10245: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].pressed_position.x));
10246: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].pressed_position.y));
10247: mouse.buttons[idx].pressed_times = 0;
10248: } else {
10249: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
10250: }
10251: REG16(AX) = mouse.get_buttons();
10252: }
10253:
10254: inline void msdos_int_33h_0006h()
10255: {
10256: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
10257: int idx = REG16(BX);
10258: REG16(BX) = mouse.buttons[idx].released_times;
10259: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].released_position.x));
10260: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].released_position.y));
10261: mouse.buttons[idx].released_times = 0;
10262: } else {
10263: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
10264: }
10265: REG16(AX) = mouse.get_buttons();
10266: }
10267:
10268: inline void msdos_int_33h_0007h()
10269: {
10270: mouse.min_position.x = min(REG16(CX), REG16(DX));
10271: mouse.max_position.x = max(REG16(CX), REG16(DX));
10272: }
10273:
10274: inline void msdos_int_33h_0008h()
10275: {
10276: mouse.min_position.y = min(REG16(CX), REG16(DX));
10277: mouse.max_position.y = max(REG16(CX), REG16(DX));
10278: }
10279:
10280: inline void msdos_int_33h_0009h()
10281: {
10282: mouse.hot_spot[0] = REG16(BX);
10283: mouse.hot_spot[1] = REG16(CX);
10284: }
10285:
10286: inline void msdos_int_33h_000bh()
10287: {
10288: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
10289: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
10290: mouse.prev_position.x = mouse.position.x;
10291: mouse.prev_position.y = mouse.position.y;
10292: REG16(CX) = dx;
10293: REG16(DX) = dy;
10294: }
10295:
10296: inline void msdos_int_33h_000ch()
10297: {
10298: mouse.call_mask = REG16(CX);
10299: mouse.call_addr.w.l = REG16(DX);
10300: mouse.call_addr.w.h = SREG(ES);
10301: }
10302:
10303: inline void msdos_int_33h_000fh()
10304: {
10305: mouse.mickey.x = REG16(CX);
10306: mouse.mickey.y = REG16(DX);
10307: }
10308:
10309: inline void msdos_int_33h_0011h()
10310: {
10311: REG16(AX) = 0xffff;
10312: REG16(BX) = MAX_MOUSE_BUTTONS;
10313: }
10314:
10315: inline void msdos_int_33h_0014h()
10316: {
10317: UINT16 old_mask = mouse.call_mask;
10318: UINT16 old_ofs = mouse.call_addr.w.l;
10319: UINT16 old_seg = mouse.call_addr.w.h;
10320:
10321: mouse.call_mask = REG16(CX);
10322: mouse.call_addr.w.l = REG16(DX);
10323: mouse.call_addr.w.h = SREG(ES);
10324:
10325: REG16(CX) = old_mask;
10326: REG16(DX) = old_ofs;
10327: SREG(ES) = old_seg;
10328: i386_load_segment_descriptor(ES);
10329: }
10330:
10331: inline void msdos_int_33h_0015h()
10332: {
10333: REG16(BX) = sizeof(mouse);
10334: }
10335:
10336: inline void msdos_int_33h_0016h()
10337: {
10338: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
10339: }
10340:
10341: inline void msdos_int_33h_0017h()
10342: {
10343: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
10344: }
10345:
10346: inline void msdos_int_33h_001ah()
10347: {
10348: mouse.sensitivity[0] = REG16(BX);
10349: mouse.sensitivity[1] = REG16(CX);
10350: mouse.sensitivity[2] = REG16(DX);
10351: }
10352:
10353: inline void msdos_int_33h_001bh()
10354: {
10355: REG16(BX) = mouse.sensitivity[0];
10356: REG16(CX) = mouse.sensitivity[1];
10357: REG16(DX) = mouse.sensitivity[2];
10358: }
10359:
10360: inline void msdos_int_33h_001dh()
10361: {
10362: mouse.display_page = REG16(BX);
10363: }
10364:
10365: inline void msdos_int_33h_001eh()
10366: {
10367: REG16(BX) = mouse.display_page;
10368: }
10369:
10370: inline void msdos_int_33h_0021h()
10371: {
10372: REG16(AX) = 0xffff;
10373: REG16(BX) = MAX_MOUSE_BUTTONS;
10374: }
10375:
10376: inline void msdos_int_33h_0022h()
10377: {
10378: mouse.language = REG16(BX);
10379: }
10380:
10381: inline void msdos_int_33h_0023h()
10382: {
10383: REG16(BX) = mouse.language;
10384: }
10385:
10386: inline void msdos_int_33h_0024h()
10387: {
10388: REG16(BX) = 0x0805; // V8.05
10389: REG16(CX) = 0x0400; // PS/2
10390: }
10391:
10392: inline void msdos_int_33h_0026h()
10393: {
10394: REG16(BX) = 0x0000;
10395: REG16(CX) = mouse.max_position.x;
10396: REG16(DX) = mouse.max_position.y;
10397: }
10398:
10399: inline void msdos_int_33h_002ah()
10400: {
10401: REG16(AX) = mouse.active ? 0 : 0xffff;
10402: REG16(BX) = mouse.hot_spot[0];
10403: REG16(CX) = mouse.hot_spot[1];
10404: REG16(DX) = 4; // PS/2
10405: }
10406:
10407: inline void msdos_int_33h_0031h()
10408: {
10409: REG16(AX) = mouse.min_position.x;
10410: REG16(BX) = mouse.min_position.y;
10411: REG16(CX) = mouse.max_position.x;
10412: REG16(DX) = mouse.max_position.y;
10413: }
10414:
10415: inline void msdos_int_33h_0032h()
10416: {
10417: REG16(AX) = 0;
10418: // REG16(AX) |= 0x8000; // 0025h
10419: REG16(AX) |= 0x4000; // 0026h
10420: // REG16(AX) |= 0x2000; // 0027h
10421: // REG16(AX) |= 0x1000; // 0028h
10422: // REG16(AX) |= 0x0800; // 0029h
10423: REG16(AX) |= 0x0400; // 002ah
10424: // REG16(AX) |= 0x0200; // 002bh
10425: // REG16(AX) |= 0x0100; // 002ch
10426: // REG16(AX) |= 0x0080; // 002dh
10427: // REG16(AX) |= 0x0040; // 002eh
10428: REG16(AX) |= 0x0020; // 002fh
10429: // REG16(AX) |= 0x0010; // 0030h
10430: REG16(AX) |= 0x0008; // 0031h
10431: REG16(AX) |= 0x0004; // 0032h
10432: // REG16(AX) |= 0x0002; // 0033h
10433: // REG16(AX) |= 0x0001; // 0034h
10434: }
10435:
1.1.1.19 root 10436: inline void msdos_int_67h_40h()
10437: {
10438: if(!support_ems) {
10439: REG8(AH) = 0x84;
10440: } else {
10441: REG8(AH) = 0x00;
10442: }
10443: }
10444:
10445: inline void msdos_int_67h_41h()
10446: {
10447: if(!support_ems) {
10448: REG8(AH) = 0x84;
10449: } else {
10450: REG8(AH) = 0x00;
10451: REG16(BX) = EMS_TOP >> 4;
10452: }
10453: }
10454:
10455: inline void msdos_int_67h_42h()
10456: {
10457: if(!support_ems) {
10458: REG8(AH) = 0x84;
10459: } else {
10460: REG8(AH) = 0x00;
10461: REG16(BX) = free_ems_pages;
10462: REG16(DX) = MAX_EMS_PAGES;
10463: }
10464: }
10465:
10466: inline void msdos_int_67h_43h()
10467: {
10468: if(!support_ems) {
10469: REG8(AH) = 0x84;
10470: } else if(REG16(BX) > MAX_EMS_PAGES) {
10471: REG8(AH) = 0x87;
10472: } else if(REG16(BX) > free_ems_pages) {
10473: REG8(AH) = 0x88;
10474: } else if(REG16(BX) == 0) {
10475: REG8(AH) = 0x89;
10476: } else {
1.1.1.31 root 10477: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 10478: if(!ems_handles[i].allocated) {
10479: ems_allocate_pages(i, REG16(BX));
10480: REG8(AH) = 0x00;
10481: REG16(DX) = i;
10482: return;
10483: }
10484: }
10485: REG8(AH) = 0x85;
10486: }
10487: }
10488:
10489: inline void msdos_int_67h_44h()
10490: {
10491: if(!support_ems) {
10492: REG8(AH) = 0x84;
1.1.1.31 root 10493: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 10494: REG8(AH) = 0x83;
10495: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
10496: REG8(AH) = 0x8a;
10497: // } else if(!(REG8(AL) < 4)) {
10498: // REG8(AH) = 0x8b;
10499: } else if(REG16(BX) == 0xffff) {
10500: ems_unmap_page(REG8(AL) & 3);
10501: REG8(AH) = 0x00;
10502: } else {
10503: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
10504: REG8(AH) = 0x00;
10505: }
10506: }
10507:
10508: inline void msdos_int_67h_45h()
10509: {
10510: if(!support_ems) {
10511: REG8(AH) = 0x84;
1.1.1.31 root 10512: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 10513: REG8(AH) = 0x83;
10514: } else {
10515: ems_release_pages(REG16(DX));
10516: REG8(AH) = 0x00;
10517: }
10518: }
10519:
10520: inline void msdos_int_67h_46h()
10521: {
10522: if(!support_ems) {
10523: REG8(AH) = 0x84;
10524: } else {
1.1.1.29 root 10525: // REG16(AX) = 0x0032; // EMS 3.2
10526: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 10527: }
10528: }
10529:
10530: inline void msdos_int_67h_47h()
10531: {
10532: // NOTE: the map data should be stored in the specified ems page, not process data
10533: process_t *process = msdos_process_info_get(current_psp);
10534:
10535: if(!support_ems) {
10536: REG8(AH) = 0x84;
1.1.1.31 root 10537: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 10538: // REG8(AH) = 0x83;
10539: } else if(process->ems_pages_stored) {
10540: REG8(AH) = 0x8d;
10541: } else {
10542: for(int i = 0; i < 4; i++) {
10543: process->ems_pages[i].handle = ems_pages[i].handle;
10544: process->ems_pages[i].page = ems_pages[i].page;
10545: process->ems_pages[i].mapped = ems_pages[i].mapped;
10546: }
10547: process->ems_pages_stored = true;
10548: REG8(AH) = 0x00;
10549: }
10550: }
10551:
10552: inline void msdos_int_67h_48h()
10553: {
10554: // NOTE: the map data should be restored from the specified ems page, not process data
10555: process_t *process = msdos_process_info_get(current_psp);
10556:
10557: if(!support_ems) {
10558: REG8(AH) = 0x84;
1.1.1.31 root 10559: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 10560: // REG8(AH) = 0x83;
10561: } else if(!process->ems_pages_stored) {
10562: REG8(AH) = 0x8e;
10563: } else {
10564: for(int i = 0; i < 4; i++) {
10565: if(process->ems_pages[i].mapped) {
10566: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
10567: } else {
10568: ems_unmap_page(i);
10569: }
10570: }
10571: process->ems_pages_stored = false;
10572: REG8(AH) = 0x00;
10573: }
10574: }
10575:
10576: inline void msdos_int_67h_4bh()
10577: {
10578: if(!support_ems) {
10579: REG8(AH) = 0x84;
10580: } else {
10581: REG8(AH) = 0x00;
10582: REG16(BX) = 0;
1.1.1.31 root 10583: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 10584: if(ems_handles[i].allocated) {
10585: REG16(BX)++;
10586: }
10587: }
10588: }
10589: }
10590:
10591: inline void msdos_int_67h_4ch()
10592: {
10593: if(!support_ems) {
10594: REG8(AH) = 0x84;
1.1.1.31 root 10595: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 10596: REG8(AH) = 0x83;
10597: } else {
10598: REG8(AH) = 0x00;
10599: REG16(BX) = ems_handles[REG16(DX)].pages;
10600: }
10601: }
10602:
10603: inline void msdos_int_67h_4dh()
10604: {
10605: if(!support_ems) {
10606: REG8(AH) = 0x84;
10607: } else {
10608: REG8(AH) = 0x00;
10609: REG16(BX) = 0;
1.1.1.31 root 10610: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 10611: if(ems_handles[i].allocated) {
10612: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
10613: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
10614: REG16(BX)++;
10615: }
10616: }
10617: }
10618: }
10619:
1.1.1.20 root 10620: inline void msdos_int_67h_4eh()
10621: {
10622: if(!support_ems) {
10623: REG8(AH) = 0x84;
10624: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
10625: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
10626: // save page map
10627: for(int i = 0; i < 4; i++) {
10628: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
10629: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
10630: }
10631: }
10632: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
10633: // restore page map
10634: for(int i = 0; i < 4; i++) {
10635: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
10636: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
10637:
1.1.1.31 root 10638: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 10639: ems_map_page(i, handle, page);
10640: } else {
10641: ems_unmap_page(i);
10642: }
10643: }
10644: }
10645: REG8(AH) = 0x00;
10646: } else if(REG8(AL) == 0x03) {
10647: REG8(AH) = 0x00;
1.1.1.21 root 10648: REG8(AL) = 4 * 4;
10649: } else {
1.1.1.22 root 10650: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.21 root 10651: REG8(AH) = 0x8f;
10652: }
10653: }
10654:
10655: inline void msdos_int_67h_4fh()
10656: {
10657: if(!support_ems) {
10658: REG8(AH) = 0x84;
10659: } else if(REG8(AL) == 0x00) {
10660: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
10661:
10662: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
10663: for(int i = 0; i < count; i++) {
10664: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
10665: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
10666:
10667: // if(!(physical < 4)) {
10668: // REG8(AH) = 0x8b;
10669: // return;
10670: // }
10671: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
10672: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
10673: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
10674: }
10675: REG8(AH) = 0x00;
10676: } else if(REG8(AL) == 0x01) {
10677: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
10678:
10679: for(int i = 0; i < count; i++) {
10680: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
10681: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
10682: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
10683: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
10684:
10685: // if(!(physical < 4)) {
10686: // REG8(AH) = 0x8b;
10687: // return;
10688: // } else
1.1.1.31 root 10689: if(!(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
1.1.1.21 root 10690: REG8(AH) = 0x83;
10691: return;
10692: } else if(logical == 0xffff) {
10693: ems_unmap_page(physical & 3);
10694: } else if(logical < ems_handles[handle].pages) {
10695: ems_map_page(physical & 3, handle, logical);
10696: } else {
10697: REG8(AH) = 0x8a;
10698: return;
10699: }
10700: }
10701: REG8(AH) = 0x00;
10702: } else if(REG8(AL) == 0x02) {
10703: REG8(AH) = 0x00;
10704: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 10705: } else {
1.1.1.22 root 10706: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10707: REG8(AH) = 0x8f;
10708: }
10709: }
10710:
10711: inline void msdos_int_67h_50h()
10712: {
10713: if(!support_ems) {
10714: REG8(AH) = 0x84;
1.1.1.31 root 10715: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 10716: REG8(AH) = 0x83;
10717: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
10718: for(int i = 0; i < REG16(CX); i++) {
10719: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
10720: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
10721:
10722: if(REG8(AL) == 0x01) {
10723: physical = ((physical << 4) - EMS_TOP) / 0x4000;
10724: }
10725: // if(!(physical < 4)) {
10726: // REG8(AH) = 0x8b;
10727: // return;
10728: // } else
10729: if(logical == 0xffff) {
10730: ems_unmap_page(physical & 3);
10731: } else if(logical < ems_handles[REG16(DX)].pages) {
10732: ems_map_page(physical & 3, REG16(DX), logical);
10733: } else {
10734: REG8(AH) = 0x8a;
10735: return;
10736: }
10737: }
10738: REG8(AH) = 0x00;
10739: } else {
1.1.1.22 root 10740: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10741: REG8(AH) = 0x8f;
10742: }
10743: }
10744:
1.1.1.19 root 10745: inline void msdos_int_67h_51h()
10746: {
10747: if(!support_ems) {
10748: REG8(AH) = 0x84;
1.1.1.31 root 10749: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 10750: REG8(AH) = 0x83;
10751: } else if(REG16(BX) > MAX_EMS_PAGES) {
10752: REG8(AH) = 0x87;
10753: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
10754: REG8(AH) = 0x88;
10755: } else {
10756: ems_reallocate_pages(REG16(DX), REG16(BX));
10757: REG8(AH) = 0x00;
10758: }
10759: }
10760:
1.1.1.20 root 10761: inline void msdos_int_67h_52h()
10762: {
10763: if(!support_ems) {
10764: REG8(AH) = 0x84;
1.1.1.31 root 10765: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10766: // REG8(AH) = 0x83;
1.1.1.20 root 10767: } else if(REG8(AL) == 0x00) {
10768: REG8(AL) = 0x00; // handle is volatile
10769: REG8(AH) = 0x00;
10770: } else if(REG8(AL) == 0x01) {
10771: if(REG8(BL) == 0x00) {
10772: REG8(AH) = 0x00;
10773: } else {
10774: REG8(AH) = 0x90; // undefined attribute type
10775: }
10776: } else if(REG8(AL) == 0x02) {
10777: REG8(AL) = 0x00; // only volatile handles supported
10778: REG8(AH) = 0x00;
10779: } else {
1.1.1.22 root 10780: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10781: REG8(AH) = 0x8f;
10782: }
10783: }
10784:
1.1.1.19 root 10785: inline void msdos_int_67h_53h()
10786: {
10787: if(!support_ems) {
10788: REG8(AH) = 0x84;
1.1.1.31 root 10789: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 10790: REG8(AH) = 0x83;
10791: } else if(REG8(AL) == 0x00) {
10792: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
10793: REG8(AH) = 0x00;
10794: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 10795: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 10796: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
10797: REG8(AH) = 0xa1;
10798: return;
10799: }
10800: }
10801: REG8(AH) = 0x00;
10802: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
10803: } else {
1.1.1.22 root 10804: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10805: REG8(AH) = 0x8f;
1.1.1.19 root 10806: }
10807: }
10808:
10809: inline void msdos_int_67h_54h()
10810: {
10811: if(!support_ems) {
10812: REG8(AH) = 0x84;
10813: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 10814: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 10815: if(ems_handles[i].allocated) {
10816: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
10817: } else {
10818: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
10819: }
10820: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
10821: }
10822: REG8(AH) = 0x00;
10823: REG8(AL) = MAX_EMS_HANDLES;
10824: } else if(REG8(AL) == 0x01) {
10825: REG8(AH) = 0xa0; // not found
1.1.1.31 root 10826: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 10827: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
10828: REG8(AH) = 0x00;
10829: REG16(DX) = i;
10830: break;
10831: }
10832: }
10833: } else if(REG8(AL) == 0x02) {
10834: REG8(AH) = 0x00;
10835: REG16(BX) = MAX_EMS_HANDLES;
10836: } else {
1.1.1.22 root 10837: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10838: REG8(AH) = 0x8f;
10839: }
10840: }
10841:
10842: inline void msdos_int_67h_57h_tmp()
10843: {
10844: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
10845: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
10846: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
10847: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
10848: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
10849: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
10850: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
10851: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
10852: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
10853:
1.1.1.32! root 10854: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 10855: UINT32 src_addr, dest_addr;
10856: UINT32 src_addr_max, dest_addr_max;
10857:
10858: if(src_type == 0) {
10859: src_buffer = mem;
10860: src_addr = (src_seg << 4) + src_ofs;
10861: src_addr_max = MAX_MEM;
10862: } else {
1.1.1.31 root 10863: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 10864: REG8(AH) = 0x83;
10865: return;
10866: } else if(!(src_seg < ems_handles[src_handle].pages)) {
10867: REG8(AH) = 0x8a;
10868: return;
10869: }
1.1.1.32! root 10870: if(ems_handles[src_handle].buffer != NULL) {
! 10871: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
! 10872: }
1.1.1.20 root 10873: src_addr = src_ofs;
1.1.1.32! root 10874: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 10875: }
10876: if(dest_type == 0) {
10877: dest_buffer = mem;
10878: dest_addr = (dest_seg << 4) + dest_ofs;
10879: dest_addr_max = MAX_MEM;
10880: } else {
1.1.1.31 root 10881: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 10882: REG8(AH) = 0x83;
10883: return;
10884: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
10885: REG8(AH) = 0x8a;
10886: return;
10887: }
1.1.1.32! root 10888: if(ems_handles[dest_handle].buffer != NULL) {
! 10889: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
! 10890: }
1.1.1.20 root 10891: dest_addr = dest_ofs;
1.1.1.32! root 10892: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 10893: }
1.1.1.32! root 10894: if(src_buffer != NULL && dest_buffer != NULL) {
! 10895: for(int i = 0; i < copy_length; i++) {
! 10896: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
! 10897: if(REG8(AL) == 0x00) {
! 10898: dest_buffer[dest_addr++] = src_buffer[src_addr++];
! 10899: } else if(REG8(AL) == 0x01) {
! 10900: UINT8 tmp = dest_buffer[dest_addr];
! 10901: dest_buffer[dest_addr++] = src_buffer[src_addr];
! 10902: src_buffer[src_addr++] = tmp;
! 10903: }
! 10904: } else {
! 10905: REG8(AH) = 0x93;
! 10906: return;
1.1.1.20 root 10907: }
10908: }
1.1.1.32! root 10909: REG8(AH) = 0x00;
! 10910: } else {
! 10911: REG8(AH) = 0x80;
1.1.1.20 root 10912: }
10913: }
10914:
10915: inline void msdos_int_67h_57h()
10916: {
10917: if(!support_ems) {
10918: REG8(AH) = 0x84;
10919: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
10920: struct {
10921: UINT16 handle;
10922: UINT16 page;
10923: bool mapped;
10924: } tmp_pages[4];
10925:
10926: // unmap pages to copy memory data to ems buffer
10927: for(int i = 0; i < 4; i++) {
10928: tmp_pages[i].handle = ems_pages[i].handle;
10929: tmp_pages[i].page = ems_pages[i].page;
10930: tmp_pages[i].mapped = ems_pages[i].mapped;
10931: ems_unmap_page(i);
10932: }
10933:
10934: // run move/exchange operation
10935: msdos_int_67h_57h_tmp();
10936:
10937: // restore unmapped pages
10938: for(int i = 0; i < 4; i++) {
10939: if(tmp_pages[i].mapped) {
10940: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
10941: }
10942: }
10943: } else {
1.1.1.22 root 10944: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10945: REG8(AH) = 0x8f;
10946: }
10947: }
10948:
10949: inline void msdos_int_67h_58h()
10950: {
10951: if(!support_ems) {
10952: REG8(AH) = 0x84;
10953: } else if(REG8(AL) == 0x00) {
10954: for(int i = 0; i < 4; i++) {
1.1.1.30 root 10955: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
10956: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 10957: }
10958: REG8(AH) = 0x00;
10959: REG16(CX) = 4;
10960: } else if(REG8(AL) == 0x01) {
10961: REG8(AH) = 0x00;
10962: REG16(CX) = 4;
10963: } else {
1.1.1.22 root 10964: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10965: REG8(AH) = 0x8f;
10966: }
10967: }
10968:
10969: inline void msdos_int_67h_5ah()
10970: {
10971: if(!support_ems) {
1.1.1.19 root 10972: REG8(AH) = 0x84;
1.1.1.20 root 10973: } else if(REG16(BX) > MAX_EMS_PAGES) {
10974: REG8(AH) = 0x87;
10975: } else if(REG16(BX) > free_ems_pages) {
10976: REG8(AH) = 0x88;
10977: // } else if(REG16(BX) == 0) {
10978: // REG8(AH) = 0x89;
10979: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 10980: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 10981: if(!ems_handles[i].allocated) {
10982: ems_allocate_pages(i, REG16(BX));
10983: REG8(AH) = 0x00;
10984: REG16(DX) = i;
10985: return;
10986: }
10987: }
10988: REG8(AH) = 0x85;
10989: } else {
1.1.1.22 root 10990: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 10991: REG8(AH) = 0x8f;
1.1.1.19 root 10992: }
10993: }
10994:
1.1.1.30 root 10995: inline void msdos_int_67h_deh()
10996: {
10997: REG8(AH) = 0x84;
10998: }
10999:
1.1.1.19 root 11000: #ifdef SUPPORT_XMS
11001:
1.1.1.32! root 11002: void msdos_xms_init()
1.1.1.26 root 11003: {
1.1.1.30 root 11004: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
11005: emb_handle_top->address = EMB_TOP;
11006: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 11007: xms_a20_local_enb_count = 0;
11008: }
11009:
1.1.1.32! root 11010: void msdos_xms_finish()
! 11011: {
! 11012: msdos_xms_release();
! 11013: }
! 11014:
! 11015: void msdos_xms_release()
1.1.1.30 root 11016: {
11017: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
11018: emb_handle_t *next_handle = emb_handle->next;
11019: free(emb_handle);
11020: emb_handle = next_handle;
11021: }
11022: }
11023:
11024: emb_handle_t *msdos_xms_get_emb_handle(int handle)
11025: {
11026: if(handle != 0) {
11027: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
11028: if(emb_handle->handle == handle) {
11029: return(emb_handle);
11030: }
11031: }
11032: }
11033: return(NULL);
11034: }
11035:
11036: int msdos_xms_get_unused_emb_handle_id()
11037: {
11038: for(int handle = 1;; handle++) {
11039: if(msdos_xms_get_emb_handle(handle) == NULL) {
11040: return(handle);
11041: }
11042: }
11043: return(0);
11044: }
11045:
11046: int msdos_xms_get_unused_emb_handle_count()
11047: {
11048: int count = 64; //255;
11049:
11050: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
11051: if(emb_handle->handle != 0) {
11052: if(--count == 1) {
11053: break;
11054: }
11055: }
11056: }
11057: return(count);
11058: }
11059:
11060: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
11061: {
11062: if(emb_handle->size_kb > size_kb) {
11063: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
11064:
11065: new_handle->address = emb_handle->address + size_kb * 1024;
11066: new_handle->size_kb = emb_handle->size_kb - size_kb;
11067: emb_handle->size_kb = size_kb;
11068:
11069: new_handle->prev = emb_handle;
11070: new_handle->next = emb_handle->next;
11071: if(emb_handle->next != NULL) {
11072: emb_handle->next->prev = new_handle;
11073: }
11074: emb_handle->next = new_handle;
11075: }
11076: }
11077:
11078: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
11079: {
11080: emb_handle_t *next_handle = emb_handle->next;
11081:
11082: if(next_handle != NULL) {
11083: emb_handle->size_kb += next_handle->size_kb;
11084:
11085: if(next_handle->next != NULL) {
11086: next_handle->next->prev = emb_handle;
11087: }
11088: emb_handle->next = next_handle->next;
11089: free(next_handle);
11090: }
11091: }
11092:
11093: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
11094: {
11095: emb_handle_t *target_handle = NULL;
11096:
11097: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
11098: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
11099: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
11100: target_handle = emb_handle;
11101: }
11102: }
11103: }
11104: if(target_handle != NULL) {
11105: if(target_handle->size_kb > size_kb) {
11106: msdos_xms_split_emb_handle(target_handle, size_kb);
11107: }
11108: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
11109: return(target_handle);
11110: }
11111: return(NULL);
11112: }
11113:
11114: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
11115: {
11116: emb_handle_t *prev_handle = emb_handle->prev;
11117: emb_handle_t *next_handle = emb_handle->next;
11118:
11119: if(prev_handle != NULL && prev_handle->handle == 0) {
11120: msdos_xms_combine_emb_handles(prev_handle);
11121: emb_handle = prev_handle;
11122: }
11123: if(next_handle != NULL && next_handle->handle == 0) {
11124: msdos_xms_combine_emb_handles(emb_handle);
11125: }
11126: emb_handle->handle = 0;
11127: }
11128:
1.1.1.19 root 11129: inline void msdos_call_xms_00h()
11130: {
1.1.1.29 root 11131: #if defined(HAS_I386)
11132: REG16(AX) = 0x0300; // V3.00 (XMS Version)
11133: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
11134: #else
11135: REG16(AX) = 0x0200; // V2.00 (XMS Version)
11136: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
11137: #endif
11138: // REG16(DX) = 0x0000; // HMA does not exist
11139: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 11140: }
11141:
11142: inline void msdos_call_xms_01h()
11143: {
1.1.1.29 root 11144: if(REG8(AL) == 0x40) {
11145: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
11146: // DX=KB free extended memory returned by last call of function 08h
11147: REG16(AX) = 0x0000;
11148: REG8(BL) = 0x91;
11149: REG16(DX) = xms_dx_after_call_08h;
11150: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
11151: REG16(AX) = 0x0000;
11152: REG8(BL) = 0x81; // Vdisk was detected
11153: #ifdef SUPPORT_HMA
11154: } else if(is_hma_used_by_int_2fh) {
11155: REG16(AX) = 0x0000;
11156: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
11157: } else if(is_hma_used_by_xms) {
11158: REG16(AX) = 0x0000;
11159: REG8(BL) = 0x91; // HMA is already in use
11160: } else {
11161: REG16(AX) = 0x0001;
11162: is_hma_used_by_xms = true;
11163: #else
11164: } else {
11165: REG16(AX) = 0x0000;
11166: REG8(BL) = 0x91; // HMA is already in use
11167: #endif
11168: }
1.1.1.19 root 11169: }
11170:
11171: inline void msdos_call_xms_02h()
11172: {
1.1.1.29 root 11173: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
11174: REG16(AX) = 0x0000;
11175: REG8(BL) = 0x81; // Vdisk was detected
11176: #ifdef SUPPORT_HMA
11177: } else if(is_hma_used_by_int_2fh) {
11178: REG16(AX) = 0x0000;
11179: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
11180: } else if(!is_hma_used_by_xms) {
11181: REG16(AX) = 0x0000;
11182: REG8(BL) = 0x93; // HMA is not allocated
11183: } else {
11184: REG16(AX) = 0x0001;
11185: is_hma_used_by_xms = false;
11186: // restore first free mcb in high memory area
11187: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11188: #else
11189: } else {
11190: REG16(AX) = 0x0000;
11191: REG8(BL) = 0x91; // HMA is already in use
11192: #endif
11193: }
1.1.1.19 root 11194: }
11195:
11196: inline void msdos_call_xms_03h()
11197: {
11198: i386_set_a20_line(1);
11199: REG16(AX) = 0x0001;
11200: REG8(BL) = 0x00;
11201: }
11202:
11203: inline void msdos_call_xms_04h()
11204: {
1.1.1.21 root 11205: i386_set_a20_line(0);
11206: REG16(AX) = 0x0001;
11207: REG8(BL) = 0x00;
1.1.1.19 root 11208: }
11209:
11210: inline void msdos_call_xms_05h()
11211: {
11212: i386_set_a20_line(1);
11213: REG16(AX) = 0x0001;
11214: REG8(BL) = 0x00;
1.1.1.21 root 11215: xms_a20_local_enb_count++;
1.1.1.19 root 11216: }
11217:
11218: void msdos_call_xms_06h()
11219: {
1.1.1.21 root 11220: if(xms_a20_local_enb_count > 0) {
11221: xms_a20_local_enb_count--;
11222: }
11223: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 11224: i386_set_a20_line(0);
1.1.1.21 root 11225: }
11226: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 11227: REG16(AX) = 0x0000;
11228: REG8(BL) = 0x94;
1.1.1.21 root 11229: } else {
11230: REG16(AX) = 0x0001;
11231: REG8(BL) = 0x00;
1.1.1.19 root 11232: }
11233: }
11234:
11235: inline void msdos_call_xms_07h()
11236: {
11237: REG16(AX) = (m_a20_mask >> 20) & 1;
11238: REG8(BL) = 0x00;
11239: }
11240:
11241: inline void msdos_call_xms_08h()
11242: {
11243: REG16(AX) = REG16(DX) = 0x0000;
11244:
1.1.1.30 root 11245: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
11246: if(emb_handle->handle == 0) {
11247: if(REG16(AX) < emb_handle->size_kb) {
11248: REG16(AX) = emb_handle->size_kb;
1.1.1.19 root 11249: }
1.1.1.30 root 11250: REG16(DX) += emb_handle->size_kb;
1.1.1.19 root 11251: }
11252: }
11253:
11254: if(REG16(AX) == 0 && REG16(DX) == 0) {
11255: REG8(BL) = 0xa0;
11256: } else {
11257: REG8(BL) = 0x00;
11258: }
1.1.1.29 root 11259: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 11260: }
11261:
1.1.1.30 root 11262: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 11263: {
1.1.1.30 root 11264: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
11265:
11266: if(emb_handle != NULL) {
11267: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
11268:
11269: REG16(AX) = 0x0001;
11270: REG16(DX) = emb_handle->handle;
11271: REG8(BL) = 0x00;
11272: } else {
11273: REG16(AX) = REG16(DX) = 0x0000;
11274: REG8(BL) = 0xa0;
1.1.1.19 root 11275: }
1.1.1.30 root 11276: }
11277:
11278: inline void msdos_call_xms_09h()
11279: {
11280: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 11281: }
11282:
11283: inline void msdos_call_xms_0ah()
11284: {
1.1.1.30 root 11285: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
11286:
11287: if(emb_handle == NULL) {
1.1.1.19 root 11288: REG16(AX) = 0x0000;
11289: REG8(BL) = 0xa2;
1.1.1.30 root 11290: } else if(emb_handle->lock > 0) {
1.1.1.19 root 11291: REG16(AX) = 0x0000;
11292: REG8(BL) = 0xab;
11293: } else {
1.1.1.30 root 11294: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 11295:
11296: REG16(AX) = 0x0001;
11297: REG8(BL) = 0x00;
11298: }
11299: }
11300:
11301: inline void msdos_call_xms_0bh()
11302: {
11303: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
11304: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
11305: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
11306: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
11307: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
11308:
11309: UINT8 *src_buffer, *dest_buffer;
11310: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 11311: emb_handle_t *emb_handle;
1.1.1.19 root 11312:
11313: if(src_handle == 0) {
11314: src_buffer = mem;
11315: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
11316: src_addr_max = MAX_MEM;
1.1.1.30 root 11317:
1.1.1.19 root 11318: } else {
1.1.1.30 root 11319: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 11320: REG16(AX) = 0x0000;
11321: REG8(BL) = 0xa3;
11322: return;
11323: }
1.1.1.30 root 11324: src_buffer = mem + emb_handle->address;
11325: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 11326: }
11327: if(dest_handle == 0) {
11328: dest_buffer = mem;
11329: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
11330: dest_addr_max = MAX_MEM;
11331: } else {
1.1.1.30 root 11332: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 11333: REG16(AX) = 0x0000;
11334: REG8(BL) = 0xa5;
11335: return;
11336: }
1.1.1.30 root 11337: dest_buffer = mem + emb_handle->address;
11338: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 11339: }
11340: for(int i = 0; i < copy_length; i++) {
11341: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
11342: dest_buffer[dest_addr++] = src_buffer[src_addr++];
11343: } else {
11344: break;
11345: }
11346: }
11347: REG16(AX) = 0x0001;
11348: REG8(BL) = 0x00;
11349: }
11350:
11351: inline void msdos_call_xms_0ch()
11352: {
1.1.1.30 root 11353: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
11354:
11355: if(emb_handle == NULL) {
1.1.1.19 root 11356: REG16(AX) = 0x0000;
11357: REG8(BL) = 0xa2;
11358: } else {
1.1.1.30 root 11359: emb_handle->lock++;
1.1.1.19 root 11360: REG16(AX) = 0x0001;
11361: REG8(BL) = 0x00;
1.1.1.30 root 11362: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
11363: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 11364: }
11365: }
11366:
11367: inline void msdos_call_xms_0dh()
11368: {
1.1.1.30 root 11369: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
11370:
11371: if(emb_handle == NULL) {
1.1.1.19 root 11372: REG16(AX) = 0x0000;
11373: REG8(BL) = 0xa2;
1.1.1.30 root 11374: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 11375: REG16(AX) = 0x0000;
11376: REG8(BL) = 0xaa;
11377: } else {
1.1.1.30 root 11378: emb_handle->lock--;
1.1.1.19 root 11379: REG16(AX) = 0x0001;
11380: REG8(BL) = 0x00;
11381: }
11382: }
11383:
11384: inline void msdos_call_xms_0eh()
11385: {
1.1.1.30 root 11386: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
11387:
11388: if(emb_handle == NULL) {
1.1.1.19 root 11389: REG16(AX) = 0x0000;
11390: REG8(BL) = 0xa2;
11391: } else {
11392: REG16(AX) = 0x0001;
1.1.1.30 root 11393: REG8(BH) = emb_handle->lock;
11394: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
11395: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 11396: }
11397: }
11398:
1.1.1.30 root 11399: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 11400: {
1.1.1.30 root 11401: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
11402:
11403: if(emb_handle == NULL) {
1.1.1.19 root 11404: REG16(AX) = 0x0000;
11405: REG8(BL) = 0xa2;
1.1.1.30 root 11406: } else if(emb_handle->lock > 0) {
1.1.1.19 root 11407: REG16(AX) = 0x0000;
11408: REG8(BL) = 0xab;
11409: } else {
1.1.1.30 root 11410: if(emb_handle->size_kb < size_kb) {
11411: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
11412: msdos_xms_combine_emb_handles(emb_handle);
11413: if(emb_handle->size_kb > size_kb) {
11414: msdos_xms_split_emb_handle(emb_handle, size_kb);
11415: }
11416: } else {
11417: int old_handle = emb_handle->handle;
11418: int old_size_kb = emb_handle->size_kb;
11419: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
11420:
11421: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
11422: msdos_xms_free_emb_handle(emb_handle);
11423:
11424: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
11425: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
11426: }
11427: emb_handle->handle = old_handle;
11428: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
11429: free(buffer);
11430: }
11431: } else if(emb_handle->size_kb > size_kb) {
11432: msdos_xms_split_emb_handle(emb_handle, size_kb);
11433: }
11434: if(emb_handle->size_kb != size_kb) {
11435: REG16(AX) = 0x0000;
11436: REG8(BL) = 0xa0;
11437: } else {
11438: REG16(AX) = 0x0001;
11439: REG8(BL) = 0x00;
11440: }
1.1.1.19 root 11441: }
11442: }
11443:
1.1.1.30 root 11444: inline void msdos_call_xms_0fh()
11445: {
11446: msdos_call_xms_0fh(REG16(BX));
11447: }
11448:
1.1.1.19 root 11449: inline void msdos_call_xms_10h()
11450: {
11451: int seg;
11452:
11453: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
11454: REG16(AX) = 0x0001;
11455: REG16(BX) = seg;
11456: } else {
11457: REG16(AX) = 0x0000;
11458: REG8(BL) = 0xb0;
11459: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
11460: }
11461: }
11462:
11463: inline void msdos_call_xms_11h()
11464: {
11465: int mcb_seg = REG16(DX) - 1;
11466: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
11467:
11468: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11469: msdos_mem_free(REG16(DX));
11470: REG16(AX) = 0x0001;
11471: REG8(BL) = 0x00;
11472: } else {
11473: REG16(AX) = 0x0000;
11474: REG8(BL) = 0xb2;
11475: }
11476: }
11477:
11478: inline void msdos_call_xms_12h()
11479: {
11480: int mcb_seg = REG16(DX) - 1;
11481: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
11482: int max_paragraphs;
11483:
11484: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11485: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
11486: REG16(AX) = 0x0001;
11487: REG8(BL) = 0x00;
11488: } else {
11489: REG16(AX) = 0x0000;
11490: REG8(BL) = 0xb0;
11491: REG16(DX) = max_paragraphs;
11492: }
11493: } else {
11494: REG16(AX) = 0x0000;
11495: REG8(BL) = 0xb2;
11496: }
11497: }
11498:
1.1.1.29 root 11499: #if defined(HAS_I386)
11500:
11501: inline void msdos_call_xms_88h()
11502: {
11503: REG32(EAX) = REG32(EDX) = 0x0000;
11504:
1.1.1.30 root 11505: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
11506: if(emb_handle->handle == 0) {
11507: if(REG32(EAX) < emb_handle->size_kb) {
11508: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 11509: }
1.1.1.30 root 11510: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 11511: }
11512: }
11513:
11514: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
11515: REG8(BL) = 0xa0;
11516: } else {
11517: REG8(BL) = 0x00;
11518: }
11519: REG32(ECX) = EMB_END - 1;
11520: }
11521:
11522: inline void msdos_call_xms_89h()
11523: {
1.1.1.30 root 11524: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 11525: }
11526:
11527: inline void msdos_call_xms_8eh()
11528: {
1.1.1.30 root 11529: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
11530:
11531: if(emb_handle == NULL) {
1.1.1.29 root 11532: REG16(AX) = 0x0000;
11533: REG8(BL) = 0xa2;
11534: } else {
11535: REG16(AX) = 0x0001;
1.1.1.30 root 11536: REG8(BH) = emb_handle->lock;
11537: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
11538: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 11539: }
11540: }
11541:
11542: inline void msdos_call_xms_8fh()
11543: {
1.1.1.30 root 11544: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 11545: }
11546:
11547: #endif
1.1.1.19 root 11548: #endif
11549:
1.1.1.26 root 11550: UINT16 msdos_get_equipment()
11551: {
11552: static UINT16 equip = 0;
11553:
11554: if(equip == 0) {
11555: #ifdef SUPPORT_FPU
11556: equip |= (1 << 1); // 80x87 coprocessor installed
11557: #endif
11558: equip |= (1 << 2); // pointing device installed (PS/2)
11559: equip |= (2 << 4); // initial video mode (80x25 color)
11560: // equip |= (1 << 8); // 0 if DMA installed
11561: equip |= (2 << 9); // number of serial ports
11562: equip |= (3 << 14); // number of printer ports (NOTE: this number is 3 on Windows 98 SE though only LPT1 exists)
1.1.1.28 root 11563:
11564: // check only A: and B: if it is floppy drive
11565: DWORD dwDrives = GetLogicalDrives();
11566: int n = 0;
11567: for(int i = 0; i < 2; i++) {
11568: if(dwDrives & (1 << i)) {
11569: char volume[] = "A:\\";
11570: volume[0] = 'A' + i;
11571: if(GetDriveType(volume) == DRIVE_REMOVABLE) {
11572: n++;
11573: }
11574: }
11575: }
11576: if(n != 0) {
11577: equip |= (1 << 0); // floppy disk(s) installed
11578: n--;
11579: equip |= (n << 6); // number of floppies installed less 1
11580: }
11581: // if(joyGetNumDevs() != 0) {
11582: // equip |= (1 << 12); // game port installed
11583: // }
1.1.1.26 root 11584: }
11585: return(equip);
11586: }
11587:
1.1 root 11588: void msdos_syscall(unsigned num)
11589: {
1.1.1.22 root 11590: #ifdef ENABLE_DEBUG_SYSCALL
11591: if(num == 0x68) {
11592: // dummy interrupt for EMS (int 67h)
11593: fprintf(fdebug, "int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11594: } else if(num == 0x69) {
11595: // dummy interrupt for XMS (call far)
11596: fprintf(fdebug, "call XMS (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11597: } else if(num == 0x6a) {
11598: // dummy interrupt for case map routine pointed in the country info
11599: } else {
11600: fprintf(fdebug, "int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11601: }
11602: #endif
1.1.1.26 root 11603: ctrl_c_pressed = ctrl_c_detected = false;
1.1.1.22 root 11604:
1.1 root 11605: switch(num) {
11606: case 0x00:
1.1.1.28 root 11607: try {
11608: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
11609: error("division by zero\n");
11610: } catch(...) {
11611: fatalerror("division by zero detected, and failed to terminate current process\n");
11612: }
1.1 root 11613: break;
11614: case 0x04:
1.1.1.28 root 11615: try {
11616: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
11617: error("overflow\n");
11618: } catch(...) {
11619: fatalerror("overflow detected, and failed to terminate current process\n");
11620: }
1.1 root 11621: break;
11622: case 0x06:
11623: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 11624: if(!ignore_illegal_insn) {
1.1.1.28 root 11625: try {
11626: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
11627: error("illegal instruction\n");
11628: } catch(...) {
11629: fatalerror("illegal instruction detected, and failed to terminate current process\n");
11630: }
1.1.1.14 root 11631: } else {
11632: #if defined(HAS_I386)
11633: m_eip++;
11634: #else
11635: m_pc++;
11636: #endif
11637: }
1.1 root 11638: break;
1.1.1.8 root 11639: case 0x08:
1.1.1.14 root 11640: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 11641: case 0x09:
11642: case 0x0a:
11643: case 0x0b:
11644: case 0x0c:
11645: case 0x0d:
11646: case 0x0e:
11647: case 0x0f:
11648: // EOI
11649: pic[0].isr &= ~(1 << (num - 0x08));
11650: pic_update();
11651: break;
1.1 root 11652: case 0x10:
11653: // PC BIOS - Video
1.1.1.14 root 11654: if(!restore_console_on_exit) {
1.1.1.15 root 11655: change_console_size(scr_width, scr_height);
1.1 root 11656: }
1.1.1.3 root 11657: m_CF = 0;
1.1 root 11658: switch(REG8(AH)) {
1.1.1.16 root 11659: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 11660: case 0x01: pcbios_int_10h_01h(); break;
11661: case 0x02: pcbios_int_10h_02h(); break;
11662: case 0x03: pcbios_int_10h_03h(); break;
11663: case 0x05: pcbios_int_10h_05h(); break;
11664: case 0x06: pcbios_int_10h_06h(); break;
11665: case 0x07: pcbios_int_10h_07h(); break;
11666: case 0x08: pcbios_int_10h_08h(); break;
11667: case 0x09: pcbios_int_10h_09h(); break;
11668: case 0x0a: pcbios_int_10h_0ah(); break;
11669: case 0x0b: break;
11670: case 0x0c: break;
11671: case 0x0d: break;
11672: case 0x0e: pcbios_int_10h_0eh(); break;
11673: case 0x0f: pcbios_int_10h_0fh(); break;
11674: case 0x10: break;
1.1.1.14 root 11675: case 0x11: pcbios_int_10h_11h(); break;
11676: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 11677: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 11678: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 11679: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 11680: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
11681: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 11682: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 11683: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
11684: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 11685: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 11686: case 0x6f: break;
1.1.1.22 root 11687: case 0x80: m_CF = 1; break; // unknown
11688: case 0x81: m_CF = 1; break; // unknown
1.1 root 11689: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 11690: case 0x83: pcbios_int_10h_83h(); break;
11691: case 0x8b: break;
11692: case 0x8c: m_CF = 1; break; // unknown
11693: case 0x8d: m_CF = 1; break; // unknown
11694: case 0x8e: m_CF = 1; break; // unknown
11695: case 0x90: pcbios_int_10h_90h(); break;
11696: case 0x91: pcbios_int_10h_91h(); break;
11697: case 0x92: break;
11698: case 0x93: break;
11699: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 11700: case 0xfa: break; // ega register interface library is not installed
1.1 root 11701: case 0xfe: pcbios_int_10h_feh(); break;
11702: case 0xff: pcbios_int_10h_ffh(); break;
11703: default:
1.1.1.22 root 11704: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11705: m_CF = 1;
1.1 root 11706: break;
11707: }
11708: break;
11709: case 0x11:
11710: // PC BIOS - Get Equipment List
1.1.1.26 root 11711: REG16(AX) = msdos_get_equipment();
1.1 root 11712: break;
11713: case 0x12:
11714: // PC BIOS - Get Memory Size
11715: REG16(AX) = MEMORY_END / 1024;
11716: break;
11717: case 0x13:
11718: // PC BIOS - Disk
1.1.1.22 root 11719: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11720: REG8(AH) = 0xff;
1.1.1.3 root 11721: m_CF = 1;
1.1 root 11722: break;
11723: case 0x14:
11724: // PC BIOS - Serial I/O
1.1.1.25 root 11725: switch(REG8(AH)) {
11726: case 0x00: pcbios_int_14h_00h(); break;
11727: case 0x01: pcbios_int_14h_01h(); break;
11728: case 0x02: pcbios_int_14h_02h(); break;
11729: case 0x03: pcbios_int_14h_03h(); break;
11730: case 0x04: pcbios_int_14h_04h(); break;
11731: case 0x05: pcbios_int_14h_05h(); break;
11732: default:
11733: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11734: break;
11735: }
1.1 root 11736: break;
11737: case 0x15:
11738: // PC BIOS
1.1.1.3 root 11739: m_CF = 0;
1.1 root 11740: switch(REG8(AH)) {
1.1.1.14 root 11741: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 11742: case 0x23: pcbios_int_15h_23h(); break;
11743: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 11744: case 0x41: break;
1.1 root 11745: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 11746: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 11747: case 0x53: pcbios_int_15h_53h(); break;
1.1 root 11748: case 0x86: pcbios_int_15h_86h(); break;
11749: case 0x87: pcbios_int_15h_87h(); break;
11750: case 0x88: pcbios_int_15h_88h(); break;
11751: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 11752: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 11753: case 0xc0: // PS/2 ???
11754: case 0xc1:
11755: case 0xc2:
1.1.1.30 root 11756: case 0xc3: // PS50+ ???
11757: case 0xc4:
1.1.1.22 root 11758: REG8(AH) = 0x86;
11759: m_CF = 1;
11760: break;
1.1.1.3 root 11761: #if defined(HAS_I386)
1.1 root 11762: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 11763: #endif
1.1 root 11764: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 11765: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 11766: default:
1.1.1.22 root 11767: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11768: REG8(AH) = 0x86;
1.1.1.3 root 11769: m_CF = 1;
1.1 root 11770: break;
11771: }
11772: break;
11773: case 0x16:
11774: // PC BIOS - Keyboard
1.1.1.3 root 11775: m_CF = 0;
1.1 root 11776: switch(REG8(AH)) {
11777: case 0x00: pcbios_int_16h_00h(); break;
11778: case 0x01: pcbios_int_16h_01h(); break;
11779: case 0x02: pcbios_int_16h_02h(); break;
11780: case 0x03: pcbios_int_16h_03h(); break;
11781: case 0x05: pcbios_int_16h_05h(); break;
11782: case 0x10: pcbios_int_16h_00h(); break;
11783: case 0x11: pcbios_int_16h_01h(); break;
11784: case 0x12: pcbios_int_16h_12h(); break;
11785: case 0x13: pcbios_int_16h_13h(); break;
11786: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 11787: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 11788: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 11789: case 0xda: break; // unknown
11790: case 0xff: break; // unknown
1.1 root 11791: default:
1.1.1.22 root 11792: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11793: break;
11794: }
11795: break;
11796: case 0x17:
11797: // PC BIOS - Printer
1.1.1.22 root 11798: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11799: break;
11800: case 0x1a:
11801: // PC BIOS - Timer
1.1.1.3 root 11802: m_CF = 0;
1.1 root 11803: switch(REG8(AH)) {
11804: case 0x00: pcbios_int_1ah_00h(); break;
11805: case 0x01: break;
11806: case 0x02: pcbios_int_1ah_02h(); break;
11807: case 0x03: break;
11808: case 0x04: pcbios_int_1ah_04h(); break;
11809: case 0x05: break;
11810: case 0x0a: pcbios_int_1ah_0ah(); break;
11811: case 0x0b: break;
1.1.1.14 root 11812: case 0x35: break; // Word Perfect Third Party Interface?
11813: case 0x36: break; // Word Perfect Third Party Interface
11814: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 11815: default:
1.1.1.22 root 11816: unimplemented_1ah("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11817: break;
11818: }
11819: break;
11820: case 0x20:
1.1.1.28 root 11821: try {
11822: msdos_process_terminate(SREG(CS), retval, 1);
11823: } catch(...) {
11824: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
11825: }
1.1 root 11826: break;
11827: case 0x21:
11828: // MS-DOS System Call
1.1.1.3 root 11829: m_CF = 0;
1.1.1.28 root 11830: try {
11831: switch(REG8(AH)) {
11832: case 0x00: msdos_int_21h_00h(); break;
11833: case 0x01: msdos_int_21h_01h(); break;
11834: case 0x02: msdos_int_21h_02h(); break;
11835: case 0x03: msdos_int_21h_03h(); break;
11836: case 0x04: msdos_int_21h_04h(); break;
11837: case 0x05: msdos_int_21h_05h(); break;
11838: case 0x06: msdos_int_21h_06h(); break;
11839: case 0x07: msdos_int_21h_07h(); break;
11840: case 0x08: msdos_int_21h_08h(); break;
11841: case 0x09: msdos_int_21h_09h(); break;
11842: case 0x0a: msdos_int_21h_0ah(); break;
11843: case 0x0b: msdos_int_21h_0bh(); break;
11844: case 0x0c: msdos_int_21h_0ch(); break;
11845: case 0x0d: msdos_int_21h_0dh(); break;
11846: case 0x0e: msdos_int_21h_0eh(); break;
11847: case 0x0f: msdos_int_21h_0fh(); break;
11848: case 0x10: msdos_int_21h_10h(); break;
11849: case 0x11: msdos_int_21h_11h(); break;
11850: case 0x12: msdos_int_21h_12h(); break;
11851: case 0x13: msdos_int_21h_13h(); break;
11852: case 0x14: msdos_int_21h_14h(); break;
11853: case 0x15: msdos_int_21h_15h(); break;
11854: case 0x16: msdos_int_21h_16h(); break;
11855: case 0x17: msdos_int_21h_17h(); break;
11856: case 0x18: msdos_int_21h_18h(); break;
11857: case 0x19: msdos_int_21h_19h(); break;
11858: case 0x1a: msdos_int_21h_1ah(); break;
11859: case 0x1b: msdos_int_21h_1bh(); break;
11860: case 0x1c: msdos_int_21h_1ch(); break;
11861: case 0x1d: msdos_int_21h_1dh(); break;
11862: case 0x1e: msdos_int_21h_1eh(); break;
11863: case 0x1f: msdos_int_21h_1fh(); break;
11864: case 0x20: msdos_int_21h_20h(); break;
11865: case 0x21: msdos_int_21h_21h(); break;
11866: case 0x22: msdos_int_21h_22h(); break;
11867: case 0x23: msdos_int_21h_23h(); break;
11868: case 0x24: msdos_int_21h_24h(); break;
11869: case 0x25: msdos_int_21h_25h(); break;
11870: case 0x26: msdos_int_21h_26h(); break;
11871: case 0x27: msdos_int_21h_27h(); break;
11872: case 0x28: msdos_int_21h_28h(); break;
11873: case 0x29: msdos_int_21h_29h(); break;
11874: case 0x2a: msdos_int_21h_2ah(); break;
11875: case 0x2b: msdos_int_21h_2bh(); break;
11876: case 0x2c: msdos_int_21h_2ch(); break;
11877: case 0x2d: msdos_int_21h_2dh(); break;
11878: case 0x2e: msdos_int_21h_2eh(); break;
11879: case 0x2f: msdos_int_21h_2fh(); break;
11880: case 0x30: msdos_int_21h_30h(); break;
11881: case 0x31: msdos_int_21h_31h(); break;
11882: case 0x32: msdos_int_21h_32h(); break;
11883: case 0x33: msdos_int_21h_33h(); break;
11884: case 0x34: msdos_int_21h_34h(); break;
11885: case 0x35: msdos_int_21h_35h(); break;
11886: case 0x36: msdos_int_21h_36h(); break;
11887: case 0x37: msdos_int_21h_37h(); break;
11888: case 0x38: msdos_int_21h_38h(); break;
11889: case 0x39: msdos_int_21h_39h(0); break;
11890: case 0x3a: msdos_int_21h_3ah(0); break;
11891: case 0x3b: msdos_int_21h_3bh(0); break;
11892: case 0x3c: msdos_int_21h_3ch(); break;
11893: case 0x3d: msdos_int_21h_3dh(); break;
11894: case 0x3e: msdos_int_21h_3eh(); break;
11895: case 0x3f: msdos_int_21h_3fh(); break;
11896: case 0x40: msdos_int_21h_40h(); break;
11897: case 0x41: msdos_int_21h_41h(0); break;
11898: case 0x42: msdos_int_21h_42h(); break;
11899: case 0x43: msdos_int_21h_43h(0); break;
11900: case 0x44: msdos_int_21h_44h(); break;
11901: case 0x45: msdos_int_21h_45h(); break;
11902: case 0x46: msdos_int_21h_46h(); break;
11903: case 0x47: msdos_int_21h_47h(0); break;
11904: case 0x48: msdos_int_21h_48h(); break;
11905: case 0x49: msdos_int_21h_49h(); break;
11906: case 0x4a: msdos_int_21h_4ah(); break;
11907: case 0x4b: msdos_int_21h_4bh(); break;
11908: case 0x4c: msdos_int_21h_4ch(); break;
11909: case 0x4d: msdos_int_21h_4dh(); break;
11910: case 0x4e: msdos_int_21h_4eh(); break;
11911: case 0x4f: msdos_int_21h_4fh(); break;
11912: case 0x50: msdos_int_21h_50h(); break;
11913: case 0x51: msdos_int_21h_51h(); break;
11914: case 0x52: msdos_int_21h_52h(); break;
11915: // 0x53: translate bios parameter block to drive param bock
11916: case 0x54: msdos_int_21h_54h(); break;
11917: case 0x55: msdos_int_21h_55h(); break;
11918: case 0x56: msdos_int_21h_56h(0); break;
11919: case 0x57: msdos_int_21h_57h(); break;
11920: case 0x58: msdos_int_21h_58h(); break;
11921: case 0x59: msdos_int_21h_59h(); break;
11922: case 0x5a: msdos_int_21h_5ah(); break;
11923: case 0x5b: msdos_int_21h_5bh(); break;
11924: case 0x5c: msdos_int_21h_5ch(); break;
11925: case 0x5d: msdos_int_21h_5dh(); break;
11926: // 0x5e: ms-network
1.1.1.30 root 11927: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 11928: case 0x60: msdos_int_21h_60h(0); break;
11929: case 0x61: msdos_int_21h_61h(); break;
11930: case 0x62: msdos_int_21h_62h(); break;
11931: case 0x63: msdos_int_21h_63h(); break;
11932: // 0x64: set device driver lockahead flag
11933: case 0x65: msdos_int_21h_65h(); break;
11934: case 0x66: msdos_int_21h_66h(); break;
11935: case 0x67: msdos_int_21h_67h(); break;
11936: case 0x68: msdos_int_21h_68h(); break;
11937: case 0x69: msdos_int_21h_69h(); break;
11938: case 0x6a: msdos_int_21h_6ah(); break;
11939: case 0x6b: msdos_int_21h_6bh(); break;
11940: case 0x6c: msdos_int_21h_6ch(0); break;
11941: // 0x6d: find first rom program
11942: // 0x6e: find next rom program
11943: // 0x6f: get/set rom scan start address
11944: // 0x70: windows95 get/set internationalization information
11945: case 0x71:
11946: // windows95 long filename functions
11947: switch(REG8(AL)) {
11948: case 0x0d: msdos_int_21h_710dh(); break;
11949: case 0x39: msdos_int_21h_39h(1); break;
11950: case 0x3a: msdos_int_21h_3ah(1); break;
11951: case 0x3b: msdos_int_21h_3bh(1); break;
11952: case 0x41: msdos_int_21h_7141h(1); break;
11953: case 0x43: msdos_int_21h_43h(1); break;
11954: case 0x47: msdos_int_21h_47h(1); break;
11955: case 0x4e: msdos_int_21h_714eh(); break;
11956: case 0x4f: msdos_int_21h_714fh(); break;
11957: case 0x56: msdos_int_21h_56h(1); break;
11958: case 0x60: msdos_int_21h_60h(1); break;
11959: case 0x6c: msdos_int_21h_6ch(1); break;
11960: case 0xa0: msdos_int_21h_71a0h(); break;
11961: case 0xa1: msdos_int_21h_71a1h(); break;
11962: case 0xa6: msdos_int_21h_71a6h(); break;
11963: case 0xa7: msdos_int_21h_71a7h(); break;
11964: case 0xa8: msdos_int_21h_71a8h(); break;
11965: // 0xa9: server create/open file
11966: case 0xaa: msdos_int_21h_71aah(); break;
11967: default:
11968: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11969: REG16(AX) = 0x7100;
11970: m_CF = 1;
11971: break;
11972: }
11973: break;
11974: // 0x72: Windows95 beta - LFN FindClose
11975: case 0x73:
11976: // windows95 fat32 functions
11977: switch(REG8(AL)) {
11978: case 0x00: msdos_int_21h_7300h(); break;
11979: // 0x01: set drive locking ???
11980: case 0x02: msdos_int_21h_7302h(); break;
11981: case 0x03: msdos_int_21h_7303h(); break;
11982: // 0x04: set dpb to use for formatting
11983: // 0x05: extended absolute disk read/write
11984: default:
11985: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11986: REG16(AX) = 0x7300;
11987: m_CF = 1;
11988: break;
11989: }
1.1 root 11990: break;
1.1.1.30 root 11991: case 0xdb: msdos_int_21h_dbh(); break;
11992: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 11993: default:
1.1.1.22 root 11994: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.28 root 11995: REG16(AX) = 0x01;
1.1.1.3 root 11996: m_CF = 1;
1.1 root 11997: break;
11998: }
1.1.1.28 root 11999: } catch(int error) {
12000: REG16(AX) = error;
12001: m_CF = 1;
12002: } catch(...) {
12003: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 12004: m_CF = 1;
1.1 root 12005: }
1.1.1.3 root 12006: if(m_CF) {
1.1.1.23 root 12007: sda_t *sda = (sda_t *)(mem + SDA_TOP);
12008: sda->extended_error_code = REG16(AX);
12009: switch(sda->extended_error_code) {
12010: case 4: // Too many open files
12011: case 8: // Insufficient memory
12012: sda->error_class = 1; // Out of resource
12013: break;
12014: case 5: // Access denied
12015: sda->error_class = 3; // Authorization
12016: break;
12017: case 7: // Memory control block destroyed
12018: sda->error_class = 4; // Internal
12019: break;
12020: case 2: // File not found
12021: case 3: // Path not found
12022: case 15: // Invaid drive specified
12023: case 18: // No more files
12024: sda->error_class = 8; // Not found
12025: break;
12026: case 32: // Sharing violation
12027: case 33: // Lock violation
12028: sda->error_class = 10; // Locked
12029: break;
12030: // case 16: // Removal of current directory attempted
12031: case 19: // Attempted write on protected disk
12032: case 21: // Drive not ready
12033: // case 29: // Write failure
12034: // case 30: // Read failure
12035: // case 82: // Cannot create subdirectory
12036: sda->error_class = 11; // Media
12037: break;
12038: case 80: // File already exists
12039: sda->error_class = 12; // Already exist
12040: break;
12041: default:
12042: sda->error_class = 13; // Unknown
12043: break;
12044: }
12045: sda->suggested_action = 1; // Retry
12046: sda->locus_of_last_error = 1; // Unknown
1.1 root 12047: }
1.1.1.26 root 12048: if(ctrl_c_checking && ctrl_c_detected) {
12049: // raise int 23h
12050: #if defined(HAS_I386)
12051: m_ext = 0; // not an external interrupt
12052: i386_trap(0x23, 1, 0);
12053: m_ext = 1;
12054: #else
12055: PREFIX86(_interrupt)(0x23);
12056: #endif
12057: }
1.1 root 12058: break;
12059: case 0x22:
12060: fatalerror("int 22h (terminate address)\n");
12061: case 0x23:
1.1.1.28 root 12062: try {
12063: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
12064: } catch(...) {
12065: fatalerror("failed to terminate the current process by int 23h\n");
12066: }
1.1 root 12067: break;
12068: case 0x24:
1.1.1.32! root 12069: /*
1.1.1.28 root 12070: try {
12071: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
12072: } catch(...) {
12073: fatalerror("failed to terminate the current process by int 24h\n");
12074: }
1.1.1.32! root 12075: */
! 12076: msdos_int_24h();
1.1 root 12077: break;
12078: case 0x25:
12079: msdos_int_25h();
12080: break;
12081: case 0x26:
12082: msdos_int_26h();
12083: break;
12084: case 0x27:
1.1.1.28 root 12085: try {
12086: msdos_int_27h();
12087: } catch(...) {
12088: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
12089: }
1.1 root 12090: break;
12091: case 0x28:
12092: Sleep(10);
12093: break;
12094: case 0x29:
12095: msdos_int_29h();
12096: break;
12097: case 0x2e:
12098: msdos_int_2eh();
12099: break;
12100: case 0x2f:
12101: // multiplex interrupt
12102: switch(REG8(AH)) {
1.1.1.22 root 12103: case 0x05: msdos_int_2fh_05h(); break;
12104: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 12105: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 12106: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 12107: case 0x14: msdos_int_2fh_14h(); break;
12108: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 12109: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 12110: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 12111: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 12112: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 12113: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 12114: case 0x46: msdos_int_2fh_46h(); break;
12115: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 12116: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 12117: case 0x4b: msdos_int_2fh_4bh(); break;
1.1 root 12118: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 12119: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.30 root 12120: case 0x80: msdos_int_2fh_80h(); break;
1.1.1.24 root 12121: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 12122: case 0xae: msdos_int_2fh_aeh(); break;
12123: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.30 root 12124: case 0xd7: msdos_int_2fh_d7h(); break;
12125: // Installation Check
12126: case 0x01: // PRINT.COM
12127: case 0x02: // PC LAN Program Redirector
12128: case 0x06: // ASSIGN
12129: case 0x08: // DRIVER.SYS
12130: case 0x10: // SHARE
12131: case 0x17: // Clibboard functions
12132: case 0x1b: // XMA2EMS.SYS
12133: case 0x23: // DR DOS 5.0 GRAFTABL
12134: case 0x27: // DR-DOR 6.0 TaskMAX
12135: case 0x2e: // Novell DOS 7 GRAFTABL
12136: case 0x45: // PROF.COM
12137: case 0x51: // ODIHELP.EXE
12138: case 0x54: // POWER.EXE
12139: case 0x56: // INTERLNK
12140: case 0x70: // License Service API
12141: case 0x7a: // Novell NetWare
12142: case 0x94: // MICRO.EXE
12143: case 0xac: // GRAPHICS.COM
12144: case 0xb0: // GRAFTABLE.COM
12145: case 0xb8: // NETWORK
12146: case 0xb9: // RECEIVER.COM
12147: case 0xbc: // EGA.SYS
12148: case 0xbf: // PC LAN Program - REDIRIFS.EXE
12149: case 0xc0: // Novell LSL.COM
12150: case 0xd2: // PCL-838.EXE
12151: case 0xd8: // Novell NetWare Lite - CLIENT.EXE
12152: switch(REG8(AL)) {
12153: case 0x00:
12154: // This is not installed
12155: // REG8(AL) = 0x00;
12156: break;
12157: default:
12158: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
12159: REG16(AX) = 0x01;
12160: m_CF = 1;
12161: break;
12162: }
12163: break;
1.1.1.22 root 12164: default:
12165: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
12166: break;
1.1 root 12167: }
12168: break;
1.1.1.24 root 12169: case 0x33:
12170: switch(REG8(AH)) {
12171: case 0x00:
12172: // Mouse
12173: switch(REG8(AL)) {
12174: case 0x00: msdos_int_33h_0000h(); break;
12175: case 0x01: msdos_int_33h_0001h(); break;
12176: case 0x02: msdos_int_33h_0002h(); break;
12177: case 0x03: msdos_int_33h_0003h(); break;
12178: case 0x04: break; // position mouse cursor
12179: case 0x05: msdos_int_33h_0005h(); break;
12180: case 0x06: msdos_int_33h_0006h(); break;
12181: case 0x07: msdos_int_33h_0007h(); break;
12182: case 0x08: msdos_int_33h_0008h(); break;
12183: case 0x09: msdos_int_33h_0009h(); break;
12184: case 0x0a: break; // define text cursor
12185: case 0x0b: msdos_int_33h_000bh(); break;
12186: case 0x0c: msdos_int_33h_000ch(); break;
12187: case 0x0d: break; // light pen emulation on
12188: case 0x0e: break; // light pen emulation off
12189: case 0x0f: msdos_int_33h_000fh(); break;
12190: case 0x10: break; // define screen region for updating
12191: case 0x11: msdos_int_33h_0011h(); break;
12192: case 0x12: REG16(AX) = 0xffff; break; // set large graphics cursor block
12193: case 0x13: break; // define double-speed threshold
12194: case 0x14: msdos_int_33h_0014h(); break;
12195: case 0x15: msdos_int_33h_0015h(); break;
12196: case 0x16: msdos_int_33h_0016h(); break;
12197: case 0x17: msdos_int_33h_0017h(); break;
12198: case 0x1a: msdos_int_33h_001ah(); break;
12199: case 0x1b: msdos_int_33h_001bh(); break;
12200: case 0x1d: msdos_int_33h_001dh(); break;
12201: case 0x1e: msdos_int_33h_001eh(); break;
12202: case 0x21: msdos_int_33h_0021h(); break;
12203: case 0x22: msdos_int_33h_0022h(); break;
12204: case 0x23: msdos_int_33h_0023h(); break;
12205: case 0x24: msdos_int_33h_0024h(); break;
12206: case 0x26: msdos_int_33h_0026h(); break;
12207: case 0x2a: msdos_int_33h_002ah(); break;
12208: case 0x2f: break; // mouse hardware reset
12209: case 0x31: msdos_int_33h_0031h(); break;
12210: case 0x32: msdos_int_33h_0032h(); break;
12211: default:
12212: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
12213: break;
12214: }
12215: break;
12216: default:
12217: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
12218: break;
12219: }
12220: break;
1.1.1.19 root 12221: case 0x68:
12222: // dummy interrupt for EMS (int 67h)
12223: switch(REG8(AH)) {
12224: case 0x40: msdos_int_67h_40h(); break;
12225: case 0x41: msdos_int_67h_41h(); break;
12226: case 0x42: msdos_int_67h_42h(); break;
12227: case 0x43: msdos_int_67h_43h(); break;
12228: case 0x44: msdos_int_67h_44h(); break;
12229: case 0x45: msdos_int_67h_45h(); break;
12230: case 0x46: msdos_int_67h_46h(); break;
12231: case 0x47: msdos_int_67h_47h(); break;
12232: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 12233: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
12234: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 12235: case 0x4b: msdos_int_67h_4bh(); break;
12236: case 0x4c: msdos_int_67h_4ch(); break;
12237: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 12238: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 12239: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 12240: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 12241: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 12242: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 12243: case 0x53: msdos_int_67h_53h(); break;
12244: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 12245: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
12246: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
12247: case 0x57: msdos_int_67h_57h(); break;
12248: case 0x58: msdos_int_67h_58h(); break;
12249: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
12250: case 0x5a: msdos_int_67h_5ah(); break;
12251: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
12252: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
12253: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.31 root 12254: // 0x60: EEMS - Get Physical Window Array
12255: // 0x61: EEMS - Generic Accelerator Card Support
12256: // 0x68: EEMS - Get Address of All Pge Frames om System
12257: // 0x69: EEMS - Map Page into Frame
12258: // 0x6a: EEMS - Page Mapping
12259: // 0xde: VCPI
1.1.1.30 root 12260: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 12261: default:
1.1.1.22 root 12262: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.19 root 12263: REG8(AH) = 0x84;
12264: break;
12265: }
12266: break;
12267: #ifdef SUPPORT_XMS
12268: case 0x69:
12269: // dummy interrupt for XMS (call far)
1.1.1.28 root 12270: try {
12271: switch(REG8(AH)) {
12272: case 0x00: msdos_call_xms_00h(); break;
12273: case 0x01: msdos_call_xms_01h(); break;
12274: case 0x02: msdos_call_xms_02h(); break;
12275: case 0x03: msdos_call_xms_03h(); break;
12276: case 0x04: msdos_call_xms_04h(); break;
12277: case 0x05: msdos_call_xms_05h(); break;
12278: case 0x06: msdos_call_xms_06h(); break;
12279: case 0x07: msdos_call_xms_07h(); break;
12280: case 0x08: msdos_call_xms_08h(); break;
12281: case 0x09: msdos_call_xms_09h(); break;
12282: case 0x0a: msdos_call_xms_0ah(); break;
12283: case 0x0b: msdos_call_xms_0bh(); break;
12284: case 0x0c: msdos_call_xms_0ch(); break;
12285: case 0x0d: msdos_call_xms_0dh(); break;
12286: case 0x0e: msdos_call_xms_0eh(); break;
12287: case 0x0f: msdos_call_xms_0fh(); break;
12288: case 0x10: msdos_call_xms_10h(); break;
12289: case 0x11: msdos_call_xms_11h(); break;
12290: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 12291: #if defined(HAS_I386)
12292: case 0x88: msdos_call_xms_88h(); break;
12293: case 0x89: msdos_call_xms_89h(); break;
12294: case 0x8e: msdos_call_xms_8eh(); break;
12295: case 0x8f: msdos_call_xms_8fh(); break;
12296: #endif
1.1.1.28 root 12297: default:
12298: unimplemented_xms("call XMS (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
12299: REG16(AX) = 0x0000;
12300: REG8(BL) = 0x80; // function not implemented
12301: break;
12302: }
12303: } catch(...) {
1.1.1.19 root 12304: REG16(AX) = 0x0000;
1.1.1.28 root 12305: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 12306: }
12307: break;
12308: #endif
12309: case 0x6a:
1.1.1.24 root 12310: // irq12 (mouse)
12311: mouse_push_ax = REG16(AX);
12312: mouse_push_bx = REG16(BX);
12313: mouse_push_cx = REG16(CX);
12314: mouse_push_dx = REG16(DX);
12315: mouse_push_si = REG16(SI);
12316: mouse_push_di = REG16(DI);
12317:
12318: if(mouse.active && mouse.call_addr.dw != 0) {
12319: REG16(AX) = mouse.status_irq;
12320: REG16(BX) = mouse.get_buttons();
12321: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
12322: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
12323: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
12324: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
12325:
12326: mem[0xfffd0 + 0x02] = 0x9a; // call far
12327: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
12328: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
12329: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
12330: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
12331: } else {
12332: mem[0xfffd0 + 0x02] = 0x90; // nop
12333: mem[0xfffd0 + 0x03] = 0x90; // nop
12334: mem[0xfffd0 + 0x04] = 0x90; // nop
12335: mem[0xfffd0 + 0x05] = 0x90; // nop
12336: mem[0xfffd0 + 0x06] = 0x90; // nop
12337: }
12338: break;
12339: case 0x6b:
12340: // end of irq12 (mouse)
12341: REG16(AX) = mouse_push_ax;
12342: REG16(BX) = mouse_push_bx;
12343: REG16(CX) = mouse_push_cx;
12344: REG16(DX) = mouse_push_dx;
12345: REG16(SI) = mouse_push_si;
12346: REG16(DI) = mouse_push_di;
12347:
12348: // EOI
12349: if((pic[1].isr &= ~(1 << 4)) == 0) {
12350: pic[0].isr &= ~(1 << 2); // master
12351: }
12352: pic_update();
12353: break;
12354: case 0x6c:
1.1.1.19 root 12355: // dummy interrupt for case map routine pointed in the country info
12356: if(REG8(AL) >= 0x80) {
12357: char tmp[2] = {0};
12358: tmp[0] = REG8(AL);
12359: my_strupr(tmp);
12360: REG8(AL) = tmp[0];
12361: }
12362: break;
1.1.1.27 root 12363: case 0x6d:
12364: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
12365: REG8(AL) = 0x86; // not supported
12366: m_CF = 1;
12367: break;
1.1.1.32! root 12368: case 0x6e:
! 12369: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
! 12370: {
! 12371: UINT16 code = REG16(AX);
! 12372: if(code & 0xf0) {
! 12373: code = (code & 7) | ((code & 0x10) >> 1);
! 12374: }
! 12375: for(int i = 0; i < array_length(param_error_table); i++) {
! 12376: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
! 12377: const char *message = NULL;
! 12378: if(active_code_page == 932) {
! 12379: message = param_error_table[i].message_japanese;
! 12380: }
! 12381: if(message == NULL) {
! 12382: message = param_error_table[i].message_english;
! 12383: }
! 12384: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
! 12385: strcpy((char *)(mem + WORK_TOP + 1), message);
! 12386:
! 12387: SREG(ES) = WORK_TOP >> 4;
! 12388: i386_load_segment_descriptor(ES);
! 12389: REG16(DI) = 0x0000;
! 12390: break;
! 12391: }
! 12392: }
! 12393: }
! 12394: break;
1.1.1.8 root 12395: case 0x70:
12396: case 0x71:
12397: case 0x72:
12398: case 0x73:
12399: case 0x74:
12400: case 0x75:
12401: case 0x76:
12402: case 0x77:
12403: // EOI
12404: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
12405: pic[0].isr &= ~(1 << 2); // master
12406: }
12407: pic_update();
12408: break;
1.1 root 12409: default:
1.1.1.22 root 12410: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 12411: break;
12412: }
12413:
12414: // update cursor position
12415: if(cursor_moved) {
12416: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23 root 12417: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 12418: if(!restore_console_on_exit) {
12419: scr_top = csbi.srWindow.Top;
12420: }
1.1 root 12421: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 12422: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 12423: cursor_moved = false;
12424: }
12425: }
12426:
12427: // init
12428:
12429: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
12430: {
12431: // init file handler
12432: memset(file_handler, 0, sizeof(file_handler));
12433: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
12434: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
12435: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 12436: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 12437: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 12438: #else
12439: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
12440: #endif
12441: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 12442: }
1.1.1.21 root 12443: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 12444: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 12445: #else
12446: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 12447: #endif
1.1.1.21 root 12448: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
12449: }
1.1 root 12450: _dup2(0, DUP_STDIN);
12451: _dup2(1, DUP_STDOUT);
12452: _dup2(2, DUP_STDERR);
1.1.1.21 root 12453: _dup2(3, DUP_STDAUX);
12454: _dup2(4, DUP_STDPRN);
1.1 root 12455:
1.1.1.24 root 12456: // init mouse
12457: memset(&mouse, 0, sizeof(mouse));
12458: mouse.max_position.x = 8 * scr_width - 1;
12459: mouse.max_position.y = 8 * scr_height - 1;
12460: mouse.mickey.x = 8;
12461: mouse.mickey.y = 16;
12462:
1.1.1.26 root 12463: #ifdef SUPPORT_XMS
12464: // init xms
12465: msdos_xms_init();
12466: #endif
12467:
1.1 root 12468: // init process
12469: memset(process, 0, sizeof(process));
12470:
1.1.1.13 root 12471: // init dtainfo
12472: msdos_dta_info_init();
12473:
1.1 root 12474: // init memory
12475: memset(mem, 0, sizeof(mem));
12476:
12477: // bios data area
1.1.1.23 root 12478: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 12479: CONSOLE_SCREEN_BUFFER_INFO csbi;
12480: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 12481: CONSOLE_FONT_INFO cfi;
12482: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
12483:
12484: int regen = min(scr_width * scr_height * 2, 0x8000);
12485: text_vram_top_address = TEXT_VRAM_TOP;
12486: text_vram_end_address = text_vram_top_address + regen;
12487: shadow_buffer_top_address = SHADOW_BUF_TOP;
12488: shadow_buffer_end_address = shadow_buffer_top_address + regen;
12489:
12490: if(regen > 0x4000) {
12491: regen = 0x8000;
12492: vram_pages = 1;
12493: } else if(regen > 0x2000) {
12494: regen = 0x4000;
12495: vram_pages = 2;
12496: } else if(regen > 0x1000) {
12497: regen = 0x2000;
12498: vram_pages = 4;
12499: } else {
12500: regen = 0x1000;
12501: vram_pages = 8;
12502: }
1.1 root 12503:
1.1.1.25 root 12504: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
12505: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 12506: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
12507: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 12508: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.26 root 12509: // *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
1.1.1.25 root 12510: // *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32! root 12511: #ifdef EXT_BIOS_TOP
1.1.1.25 root 12512: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32! root 12513: #endif
1.1.1.26 root 12514: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1 root 12515: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
12516: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 12517: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
12518: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 12519: *(UINT16 *)(mem + 0x44e) = 0;
12520: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 12521: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 12522: *(UINT8 *)(mem + 0x460) = 7;
12523: *(UINT8 *)(mem + 0x461) = 7;
12524: *(UINT8 *)(mem + 0x462) = 0;
12525: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 12526: *(UINT8 *)(mem + 0x465) = 0x09;
12527: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 12528: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
12529: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
12530: *(UINT8 *)(mem + 0x487) = 0x60;
12531: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32! root 12532: #ifdef EXT_BIOS_TOP
1.1.1.25 root 12533: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32! root 12534: #endif
1.1.1.14 root 12535:
12536: // initial screen
12537: SMALL_RECT rect;
12538: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
12539: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
12540: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
12541: for(int x = 0; x < scr_width; x++) {
12542: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
12543: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
12544: }
12545: }
1.1 root 12546:
1.1.1.19 root 12547: // init mcb
1.1 root 12548: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 12549:
12550: // iret table
12551: // note: int 2eh vector should address the routine in command.com,
12552: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
12553: // so move iret table into allocated memory block
12554: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
12555: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
12556: IRET_TOP = seg << 4;
12557: seg += IRET_SIZE >> 4;
1.1.1.25 root 12558: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 12559:
12560: // dummy xms/ems device
12561: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
12562: XMS_TOP = seg << 4;
12563: seg += XMS_SIZE >> 4;
12564:
12565: // environment
1.1 root 12566: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
12567: int env_seg = seg;
12568: int ofs = 0;
1.1.1.32! root 12569: char env_append[ENV_SIZE] = {0}, append_added = 0;
! 12570: char comspec_added = 0;
! 12571: char env_msdos_path[ENV_SIZE] = {0};
! 12572: char env_path[ENV_SIZE] = {0}, path_added = 0;
! 12573: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
! 12574: char *path, *short_path;
! 12575:
! 12576: if((path = getenv("MSDOS_APPEND")) != NULL) {
! 12577: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
! 12578: strcpy(env_append, short_path);
! 12579: }
! 12580: }
! 12581: if((path = getenv("APPEND")) != NULL) {
! 12582: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
! 12583: if(env_append[0] != '\0') {
! 12584: strcat(env_append, ";");
! 12585: }
! 12586: strcat(env_append, short_path);
! 12587: }
! 12588: }
! 12589:
! 12590: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
! 12591: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
! 12592: strcpy(comspec_path, short_path);
! 12593: }
! 12594: }
! 12595: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
! 12596: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
! 12597: strcpy(comspec_path, short_path);
! 12598: }
! 12599: }
1.1 root 12600:
1.1.1.28 root 12601: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32! root 12602: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
! 12603: strcpy(env_msdos_path, short_path);
! 12604: strcpy(env_path, short_path);
1.1.1.14 root 12605: }
12606: }
1.1.1.28 root 12607: if((path = getenv("PATH")) != NULL) {
1.1.1.32! root 12608: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
! 12609: if(env_path[0] != '\0') {
! 12610: strcat(env_path, ";");
! 12611: }
! 12612: strcat(env_path, short_path);
1.1.1.9 root 12613: }
12614: }
1.1.1.32! root 12615:
! 12616: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
! 12617: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 12618: }
1.1.1.32! root 12619: for(int i = 0; i < 4; i++) {
! 12620: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
! 12621: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
! 12622: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
! 12623: strcpy(env_temp, short_path);
! 12624: break;
! 12625: }
! 12626: }
1.1.1.24 root 12627: }
1.1.1.32! root 12628:
1.1.1.9 root 12629: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 12630: // lower to upper
1.1.1.28 root 12631: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 12632: strcpy(tmp, *p);
12633: for(int i = 0;; i++) {
12634: if(tmp[i] == '=') {
12635: tmp[i] = '\0';
12636: sprintf(name, ";%s;", tmp);
1.1.1.25 root 12637: my_strupr(name);
1.1 root 12638: tmp[i] = '=';
12639: break;
12640: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 12641: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 12642: }
12643: }
1.1.1.32! root 12644: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_TEMP;MSDOS_TMP;", name) != NULL) {
! 12645: // ignore MSDOS_(APPEND/COMSPEC/TEMP/TMP)
! 12646: } else if(standard_env && strstr(";APPEND;COMSPEC;INCLUDE;LIB;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 12647: // ignore non standard environments
12648: } else {
1.1.1.32! root 12649: if(strncmp(tmp, "APPEND=", 7) == 0) {
! 12650: if(env_append[0] != '\0') {
! 12651: sprintf(tmp, "APPEND=%s", env_append);
! 12652: } else {
! 12653: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
! 12654: }
! 12655: append_added = 1;
! 12656: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 12657: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32! root 12658: comspec_added = 1;
1.1.1.28 root 12659: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
12660: if(env_msdos_path[0] != '\0') {
12661: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
12662: } else {
12663: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
12664: }
12665: } else if(strncmp(tmp, "PATH=", 5) == 0) {
12666: if(env_path[0] != '\0') {
12667: sprintf(tmp, "PATH=%s", env_path);
12668: } else {
12669: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
12670: }
1.1.1.32! root 12671: path_added = 1;
1.1.1.28 root 12672: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
12673: if(env_temp[0] != '\0') {
12674: sprintf(tmp, "TEMP=%s", env_temp);
12675: } else {
12676: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
12677: }
1.1.1.32! root 12678: temp_added = 1;
1.1.1.28 root 12679: } else if(strncmp(tmp, "TMP=", 4) == 0) {
12680: if(env_temp[0] != '\0') {
12681: sprintf(tmp, "TMP=%s", env_temp);
12682: } else {
12683: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 12684: }
1.1.1.32! root 12685: tmp_added = 1;
1.1 root 12686: }
12687: int len = strlen(tmp);
1.1.1.14 root 12688: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 12689: fatalerror("too many environments\n");
12690: }
12691: memcpy(mem + (seg << 4) + ofs, tmp, len);
12692: ofs += len + 1;
12693: }
12694: }
1.1.1.32! root 12695: if(!append_added && env_append[0] != '\0') {
! 12696: #define SET_ENV(name, value) { \
! 12697: char tmp[ENV_SIZE]; \
! 12698: sprintf(tmp, "%s=%s", name, value); \
! 12699: int len = strlen(tmp); \
! 12700: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
! 12701: fatalerror("too many environments\n"); \
! 12702: } \
! 12703: memcpy(mem + (seg << 4) + ofs, tmp, len); \
! 12704: ofs += len + 1; \
! 12705: }
! 12706: SET_ENV("APPEND", env_append);
! 12707: }
! 12708: if(!comspec_added) {
! 12709: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
! 12710: }
! 12711: if(!path_added) {
! 12712: SET_ENV("PATH", env_path);
! 12713: }
! 12714: if(!temp_added) {
! 12715: SET_ENV("TEMP", env_temp);
! 12716: }
! 12717: if(!tmp_added) {
! 12718: SET_ENV("TMP", env_temp);
! 12719: }
1.1 root 12720: seg += (ENV_SIZE >> 4);
12721:
12722: // psp
12723: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
12724: current_psp = seg;
1.1.1.14 root 12725: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 12726: seg += (PSP_SIZE >> 4);
12727:
1.1.1.19 root 12728: // first free mcb in conventional memory
12729: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 12730: first_mcb = seg;
12731:
1.1.1.19 root 12732: // dummy mcb to link to umb
12733: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
12734:
12735: // first free mcb in upper memory block
1.1.1.8 root 12736: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 12737:
1.1.1.29 root 12738: #ifdef SUPPORT_HMA
12739: // first free mcb in high memory area
12740: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
12741: #endif
12742:
1.1.1.26 root 12743: // interrupt vector
12744: for(int i = 0; i < 0x80; i++) {
12745: *(UINT16 *)(mem + 4 * i + 0) = i;
12746: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
12747: }
1.1.1.32! root 12748: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0019; // fffd:0019 irq0 (system timer)
1.1.1.26 root 12749: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
12750: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
12751: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
12752: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
12753: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
12754: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
12755: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
12756:
1.1.1.29 root 12757: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 12758: static const struct {
12759: UINT16 attributes;
12760: char *dev_name;
12761: } dummy_devices[] = {
12762: {0x8013, "CON "},
12763: {0x8000, "AUX "},
12764: {0xa0c0, "PRN "},
12765: {0x8008, "CLOCK$ "},
12766: {0x8000, "COM1 "},
12767: {0xa0c0, "LPT1 "},
12768: {0xa0c0, "LPT2 "},
12769: {0xa0c0, "LPT3 "},
12770: {0x8000, "COM2 "},
12771: {0x8000, "COM3 "},
12772: {0x8000, "COM4 "},
1.1.1.30 root 12773: // {0xc000, "CONFIG$ "},
12774: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 12775: };
12776: static const UINT8 dummy_device_routine[] = {
12777: // from NUL device of Windows 98 SE
12778: // or word ptr ES:[BX+03],0100
12779: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
12780: // retf
12781: 0xcb,
12782: };
1.1.1.29 root 12783: device_t *last = NULL;
1.1.1.32! root 12784: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 12785: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 12786: device->next_driver.w.l = 22 + 18 * (i + 1);
12787: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 12788: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 12789: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
12790: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 12791: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 12792: last = device;
12793: }
12794: if(last != NULL) {
12795: last->next_driver.w.l = 0;
12796: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 12797: }
1.1.1.29 root 12798: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 12799:
1.1.1.25 root 12800: // dos info
12801: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
12802: dos_info->magic_word = 1;
12803: dos_info->first_mcb = MEMORY_TOP >> 4;
12804: dos_info->first_dpb.w.l = 0;
12805: dos_info->first_dpb.w.h = DPB_TOP >> 4;
12806: dos_info->first_sft.w.l = 0;
12807: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.26 root 12808: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 3rd device in IO.SYS
1.1.1.25 root 12809: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 12810: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 12811: dos_info->con_device.w.h = DEVICE_TOP >> 4;
12812: dos_info->max_sector_len = 512;
12813: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
12814: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
12815: dos_info->cds.w.l = 0;
12816: dos_info->cds.w.h = CDS_TOP >> 4;
12817: dos_info->fcb_table.w.l = 0;
12818: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
12819: dos_info->last_drive = 'Z' - 'A' + 1;
12820: dos_info->buffers_x = 20;
12821: dos_info->buffers_y = 0;
12822: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 12823: dos_info->nul_device.next_driver.w.l = 22;
12824: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 12825: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 12826: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
12827: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 12828: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
12829: dos_info->disk_buf_heads.w.l = 0;
12830: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
12831: dos_info->first_umb_fcb = UMB_TOP >> 4;
12832: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 12833: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 12834:
12835: char *env;
12836: if((env = getenv("LASTDRIVE")) != NULL) {
12837: if(env[0] >= 'A' && env[0] <= 'Z') {
12838: dos_info->last_drive = env[0] - 'A' + 1;
12839: } else if(env[0] >= 'a' && env[0] <= 'z') {
12840: dos_info->last_drive = env[0] - 'a' + 1;
12841: }
12842: }
12843: if((env = getenv("windir")) != NULL) {
12844: if(env[0] >= 'A' && env[0] <= 'Z') {
12845: dos_info->boot_drive = env[0] - 'A' + 1;
12846: } else if(env[0] >= 'a' && env[0] <= 'z') {
12847: dos_info->boot_drive = env[0] - 'a' + 1;
12848: }
12849: }
12850: #if defined(HAS_I386)
12851: dos_info->i386_or_later = 1;
12852: #else
12853: dos_info->i386_or_later = 0;
12854: #endif
12855: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
12856:
1.1.1.27 root 12857: // ems (int 67h) and xms
1.1.1.25 root 12858: device_t *xms_device = (device_t *)(mem + XMS_TOP);
12859: xms_device->next_driver.w.l = 0xffff;
12860: xms_device->next_driver.w.h = 0xffff;
12861: xms_device->attributes = 0xc000;
1.1.1.29 root 12862: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
12863: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 12864: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
12865:
1.1.1.26 root 12866: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
12867: mem[XMS_TOP + 0x13] = 0x68;
12868: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 12869: #ifdef SUPPORT_XMS
12870: if(support_xms) {
1.1.1.26 root 12871: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
12872: mem[XMS_TOP + 0x16] = 0x69;
12873: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 12874: } else
12875: #endif
1.1.1.26 root 12876: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 12877: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 12878:
1.1.1.26 root 12879: // irq12 routine (mouse)
1.1.1.24 root 12880: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
12881: mem[0xfffd0 + 0x01] = 0x6a;
12882: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
12883: mem[0xfffd0 + 0x03] = 0xff;
12884: mem[0xfffd0 + 0x04] = 0xff;
12885: mem[0xfffd0 + 0x05] = 0xff;
12886: mem[0xfffd0 + 0x06] = 0xff;
12887: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
12888: mem[0xfffd0 + 0x08] = 0x6b;
12889: mem[0xfffd0 + 0x09] = 0xcf; // iret
12890:
1.1.1.27 root 12891: // case map routine
12892: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
12893: mem[0xfffd0 + 0x0b] = 0x6c;
12894: mem[0xfffd0 + 0x0c] = 0xcb; // retf
12895:
12896: // font read routine
12897: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
12898: mem[0xfffd0 + 0x0e] = 0x6d;
12899: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 12900:
1.1.1.32! root 12901: // error message read routine
! 12902: mem[0xfffd0 + 0x10] = 0xcd; // int 6eh (dummy)
! 12903: mem[0xfffd0 + 0x11] = 0x6e;
! 12904: mem[0xfffd0 + 0x12] = 0xcb; // retf
! 12905:
1.1.1.26 root 12906: // irq0 routine (system time)
1.1.1.32! root 12907: mem[0xfffd0 + 0x19] = 0xcd; // int 1ch
! 12908: mem[0xfffd0 + 0x1a] = 0x1c;
! 12909: mem[0xfffd0 + 0x1b] = 0xea; // jmp far (IRET_TOP >> 4):0008
! 12910: mem[0xfffd0 + 0x1c] = 0x08;
! 12911: mem[0xfffd0 + 0x1d] = 0x00;
! 12912: mem[0xfffd0 + 0x1e] = ((IRET_TOP >> 4) ) & 0xff;
! 12913: mem[0xfffd0 + 0x1f] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 12914:
1.1.1.26 root 12915: // boot routine
1.1 root 12916: mem[0xffff0] = 0xf4; // halt
12917: mem[0xffff1] = 0xcd; // int 21h
12918: mem[0xffff2] = 0x21;
12919: mem[0xffff3] = 0xcb; // retf
12920:
1.1.1.24 root 12921: mem[0xffff5] = '0'; // rom date
12922: mem[0xffff6] = '2';
12923: mem[0xffff7] = '/';
12924: mem[0xffff8] = '2';
12925: mem[0xffff9] = '2';
12926: mem[0xffffa] = '/';
12927: mem[0xffffb] = '0';
12928: mem[0xffffc] = '6';
12929: mem[0xffffe] = 0xfc; // machine id
12930: mem[0xfffff] = 0x00;
12931:
1.1 root 12932: // param block
12933: // + 0: param block (22bytes)
12934: // +24: fcb1/2 (20bytes)
12935: // +44: command tail (128bytes)
12936: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
12937: param->env_seg = 0;
12938: param->cmd_line.w.l = 44;
12939: param->cmd_line.w.h = (WORK_TOP >> 4);
12940: param->fcb1.w.l = 24;
12941: param->fcb1.w.h = (WORK_TOP >> 4);
12942: param->fcb2.w.l = 24;
12943: param->fcb2.w.h = (WORK_TOP >> 4);
12944:
12945: memset(mem + WORK_TOP + 24, 0x20, 20);
12946:
12947: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
12948: if(argc > 1) {
12949: sprintf(cmd_line->cmd, " %s", argv[1]);
12950: for(int i = 2; i < argc; i++) {
12951: char tmp[128];
12952: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
12953: strcpy(cmd_line->cmd, tmp);
12954: }
12955: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
12956: } else {
12957: cmd_line->len = 0;
12958: }
12959: cmd_line->cmd[cmd_line->len] = 0x0d;
12960:
12961: // system file table
1.1.1.21 root 12962: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
12963: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 12964:
1.1.1.19 root 12965: // disk buffer header (from DOSBox)
12966: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
12967: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
12968: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
12969: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
12970: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
12971:
1.1 root 12972: // current directory structure
12973: msdos_cds_update(_getdrive() - 1);
12974:
12975: // fcb table
12976: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 12977: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 12978:
1.1.1.17 root 12979: // nls stuff
12980: msdos_nls_tables_init();
1.1 root 12981:
12982: // execute command
1.1.1.28 root 12983: try {
12984: if(msdos_process_exec(argv[0], param, 0)) {
12985: fatalerror("'%s' not found\n", argv[0]);
12986: }
12987: } catch(...) {
12988: // we should not reach here :-(
12989: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 12990: }
12991: retval = 0;
12992: return(0);
12993: }
12994:
12995: #define remove_std_file(path) { \
12996: int fd = _open(path, _O_RDONLY | _O_BINARY); \
12997: if(fd != -1) { \
12998: _lseek(fd, 0, SEEK_END); \
12999: int size = _tell(fd); \
13000: _close(fd); \
13001: if(size == 0) { \
13002: remove(path); \
13003: } \
13004: } \
13005: }
13006:
13007: void msdos_finish()
13008: {
13009: for(int i = 0; i < MAX_FILES; i++) {
13010: if(file_handler[i].valid) {
13011: _close(i);
13012: }
13013: }
1.1.1.21 root 13014: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 13015: remove_std_file("stdaux.txt");
1.1.1.21 root 13016: #endif
13017: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 13018: remove_std_file("stdprn.txt");
13019: #endif
1.1.1.30 root 13020: #ifdef SUPPORT_XMS
13021: msdos_xms_finish();
13022: #endif
1.1 root 13023: msdos_dbcs_table_finish();
13024: }
13025:
13026: /* ----------------------------------------------------------------------------
13027: PC/AT hardware emulation
13028: ---------------------------------------------------------------------------- */
13029:
13030: void hardware_init()
13031: {
1.1.1.3 root 13032: CPU_INIT_CALL(CPU_MODEL);
1.1 root 13033: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 13034: m_IF = 1;
1.1.1.3 root 13035: #if defined(HAS_I386)
1.1 root 13036: cpu_type = (REG32(EDX) >> 8) & 0x0f;
13037: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 13038: #endif
13039: i386_set_a20_line(0);
1.1.1.14 root 13040:
1.1.1.19 root 13041: ems_init();
1.1.1.25 root 13042: dma_init();
1.1 root 13043: pic_init();
1.1.1.25 root 13044: pio_init();
1.1.1.8 root 13045: #ifdef PIT_ALWAYS_RUNNING
13046: pit_init();
13047: #else
1.1 root 13048: pit_active = 0;
13049: #endif
1.1.1.25 root 13050: sio_init();
1.1.1.8 root 13051: cmos_init();
13052: kbd_init();
1.1 root 13053: }
13054:
1.1.1.10 root 13055: void hardware_finish()
13056: {
13057: #if defined(HAS_I386)
13058: vtlb_free(m_vtlb);
13059: #endif
1.1.1.19 root 13060: ems_finish();
1.1.1.25 root 13061: sio_finish();
1.1.1.10 root 13062: }
13063:
1.1.1.28 root 13064: void hardware_release()
13065: {
13066: // release hardware resources when this program will be terminated abnormally
13067: #ifdef EXPORT_DEBUG_TO_FILE
13068: if(fdebug != NULL) {
13069: fclose(fdebug);
13070: fdebug = NULL;
13071: }
13072: #endif
13073: #if defined(HAS_I386)
13074: vtlb_free(m_vtlb);
13075: #endif
13076: ems_release();
13077: sio_release();
13078: }
13079:
1.1 root 13080: void hardware_run()
13081: {
13082: int ops = 0;
13083:
1.1.1.22 root 13084: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 13085: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.22 root 13086: fdebug = fopen("debug.log", "w");
13087: #endif
1.1.1.3 root 13088: while(!m_halted) {
1.1.1.22 root 13089: #ifdef ENABLE_DEBUG_DASM
13090: if(dasm > 0) {
1.1 root 13091: char buffer[256];
1.1.1.3 root 13092: #if defined(HAS_I386)
1.1.1.22 root 13093: UINT32 flags = get_flags();
1.1.1.19 root 13094: UINT32 eip = m_eip;
1.1.1.3 root 13095: #else
1.1.1.22 root 13096: UINT32 flags = CompressFlags();
1.1.1.19 root 13097: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 13098: #endif
13099: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 13100:
1.1.1.3 root 13101: #if defined(HAS_I386)
13102: if(m_operand_size) {
1.1 root 13103: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 13104: } else
13105: #endif
13106: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.22 root 13107:
13108: fprintf(fdebug, "AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X\nDS=%04X ES=%04X SS=%04X CS=%04X IP=%04X FLAG=[%s %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
13109: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), SREG(DS), SREG(ES), SREG(SS), SREG(CS), eip,
13110: #if defined(HAS_I386)
13111: PROTECTED_MODE ? "PE" : "--",
13112: #else
13113: "--",
13114: #endif
13115: (flags & 0x40000) ? 'A' : '-',
13116: (flags & 0x20000) ? 'V' : '-',
13117: (flags & 0x10000) ? 'R' : '-',
13118: (flags & 0x04000) ? 'N' : '-',
13119: (flags & 0x02000) ? '1' : '0',
13120: (flags & 0x01000) ? '1' : '0',
13121: (flags & 0x00800) ? 'O' : '-',
13122: (flags & 0x00400) ? 'D' : '-',
13123: (flags & 0x00200) ? 'I' : '-',
13124: (flags & 0x00100) ? 'T' : '-',
13125: (flags & 0x00080) ? 'S' : '-',
13126: (flags & 0x00040) ? 'Z' : '-',
13127: (flags & 0x00010) ? 'A' : '-',
13128: (flags & 0x00004) ? 'P' : '-',
13129: (flags & 0x00001) ? 'C' : '-');
13130: fprintf(fdebug, "%04X:%04X\t%s\n", SREG(CS), (unsigned)eip, buffer);
13131: dasm--;
1.1 root 13132: }
13133: #endif
1.1.1.3 root 13134: #if defined(HAS_I386)
13135: m_cycles = 1;
1.1 root 13136: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 13137: #else
13138: CPU_EXECUTE_CALL(CPU_MODEL);
13139: #endif
1.1.1.14 root 13140: #if defined(HAS_I386)
13141: if(m_eip != m_prev_eip) {
13142: #else
13143: if(m_pc != m_prevpc) {
13144: #endif
13145: iops++;
13146: }
1.1.1.8 root 13147: if(++ops == 16384) {
1.1 root 13148: hardware_update();
13149: ops = 0;
13150: }
13151: }
1.1.1.22 root 13152: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 13153: if(fdebug != NULL) {
13154: fclose(fdebug);
13155: fdebug = NULL;
13156: }
1.1.1.22 root 13157: #endif
1.1 root 13158: }
13159:
13160: void hardware_update()
13161: {
1.1.1.8 root 13162: static UINT32 prev_time = 0;
13163: UINT32 cur_time = timeGetTime();
13164:
13165: if(prev_time != cur_time) {
13166: // update pit and raise irq0
13167: #ifndef PIT_ALWAYS_RUNNING
13168: if(pit_active)
13169: #endif
13170: {
13171: if(pit_run(0, cur_time)) {
13172: pic_req(0, 0, 1);
13173: }
13174: pit_run(1, cur_time);
13175: pit_run(2, cur_time);
13176: }
1.1.1.24 root 13177:
1.1.1.25 root 13178: // update sio and raise irq4/3
1.1.1.29 root 13179: for(int c = 0; c < 4; c++) {
1.1.1.25 root 13180: sio_update(c);
13181: }
13182:
1.1.1.24 root 13183: // update keyboard and mouse
1.1.1.14 root 13184: static UINT32 prev_tick = 0;
13185: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 13186:
1.1.1.14 root 13187: if(prev_tick != cur_tick) {
13188: // update keyboard flags
13189: UINT8 state;
1.1.1.24 root 13190: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
13191: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
13192: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
13193: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
13194: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
13195: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
13196: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
13197: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 13198: mem[0x417] = state;
13199: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
13200: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
13201: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
13202: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 13203: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
13204: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 13205: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
13206: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
13207: mem[0x418] = state;
13208:
1.1.1.24 root 13209: // update console input if needed
13210: if(!key_changed || mouse.active) {
13211: update_console_input();
13212: }
13213:
13214: // raise irq1 if key is pressed/released
13215: if(key_changed) {
1.1.1.8 root 13216: pic_req(0, 1, 1);
1.1.1.24 root 13217: key_changed = false;
13218: }
13219:
13220: // raise irq12 if mouse status is changed
13221: if(mouse.status & mouse.call_mask) {
13222: if(mouse.active) {
13223: pic_req(1, 4, 1);
13224: mouse.status_irq = mouse.status & mouse.call_mask;
13225: }
13226: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 13227: }
1.1.1.24 root 13228:
1.1.1.14 root 13229: prev_tick = cur_tick;
1.1.1.8 root 13230: }
1.1.1.24 root 13231:
1.1.1.19 root 13232: // update daily timer counter
13233: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 13234:
1.1.1.8 root 13235: prev_time = cur_time;
1.1 root 13236: }
13237: }
13238:
1.1.1.19 root 13239: // ems
13240:
13241: void ems_init()
13242: {
13243: memset(ems_handles, 0, sizeof(ems_handles));
13244: memset(ems_pages, 0, sizeof(ems_pages));
13245: free_ems_pages = MAX_EMS_PAGES;
13246: }
13247:
13248: void ems_finish()
13249: {
1.1.1.28 root 13250: ems_release();
13251: }
13252:
13253: void ems_release()
13254: {
1.1.1.31 root 13255: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 13256: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 13257: free(ems_handles[i].buffer);
13258: ems_handles[i].buffer = NULL;
13259: }
13260: }
13261: }
13262:
13263: void ems_allocate_pages(int handle, int pages)
13264: {
13265: if(pages > 0) {
13266: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
13267: } else {
13268: ems_handles[handle].buffer = NULL;
13269: }
13270: ems_handles[handle].pages = pages;
13271: ems_handles[handle].allocated = true;
13272: free_ems_pages -= pages;
13273: }
13274:
13275: void ems_reallocate_pages(int handle, int pages)
13276: {
13277: if(ems_handles[handle].allocated) {
13278: if(ems_handles[handle].pages != pages) {
13279: UINT8 *new_buffer = NULL;
13280:
13281: if(pages > 0) {
13282: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
13283: }
1.1.1.32! root 13284: if(ems_handles[handle].buffer != NULL) {
! 13285: if(new_buffer != NULL) {
1.1.1.19 root 13286: if(pages > ems_handles[handle].pages) {
13287: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
13288: } else {
13289: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
13290: }
13291: }
13292: free(ems_handles[handle].buffer);
13293: ems_handles[handle].buffer = NULL;
13294: }
13295: free_ems_pages += ems_handles[handle].pages;
13296:
13297: ems_handles[handle].buffer = new_buffer;
13298: ems_handles[handle].pages = pages;
13299: free_ems_pages -= pages;
13300: }
13301: } else {
13302: ems_allocate_pages(handle, pages);
13303: }
13304: }
13305:
13306: void ems_release_pages(int handle)
13307: {
13308: if(ems_handles[handle].allocated) {
1.1.1.32! root 13309: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 13310: free(ems_handles[handle].buffer);
13311: ems_handles[handle].buffer = NULL;
13312: }
13313: free_ems_pages += ems_handles[handle].pages;
13314: ems_handles[handle].allocated = false;
13315: }
13316: }
13317:
13318: void ems_map_page(int physical, int handle, int logical)
13319: {
13320: if(ems_pages[physical].mapped) {
13321: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
13322: return;
13323: }
13324: ems_unmap_page(physical);
13325: }
1.1.1.32! root 13326: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 13327: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
13328: }
13329: ems_pages[physical].handle = handle;
13330: ems_pages[physical].page = logical;
13331: ems_pages[physical].mapped = true;
13332: }
13333:
13334: void ems_unmap_page(int physical)
13335: {
13336: if(ems_pages[physical].mapped) {
13337: int handle = ems_pages[physical].handle;
13338: int logical = ems_pages[physical].page;
13339:
1.1.1.32! root 13340: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 13341: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
13342: }
13343: ems_pages[physical].mapped = false;
13344: }
13345: }
13346:
1.1.1.25 root 13347: // dma
1.1 root 13348:
1.1.1.25 root 13349: void dma_init()
1.1 root 13350: {
1.1.1.26 root 13351: memset(dma, 0, sizeof(dma));
1.1.1.25 root 13352: for(int c = 0; c < 2; c++) {
1.1.1.26 root 13353: // for(int ch = 0; ch < 4; ch++) {
13354: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
13355: // }
1.1.1.25 root 13356: dma_reset(c);
13357: }
1.1 root 13358: }
13359:
1.1.1.25 root 13360: void dma_reset(int c)
1.1 root 13361: {
1.1.1.25 root 13362: dma[c].low_high = false;
13363: dma[c].cmd = dma[c].req = dma[c].tc = 0;
13364: dma[c].mask = 0xff;
13365: }
13366:
13367: void dma_write(int c, UINT32 addr, UINT8 data)
13368: {
13369: int ch = (addr >> 1) & 3;
13370: UINT8 bit = 1 << (data & 3);
13371:
13372: switch(addr & 0x0f) {
13373: case 0x00: case 0x02: case 0x04: case 0x06:
13374: if(dma[c].low_high) {
13375: dma[c].ch[ch].bareg.b.h = data;
1.1 root 13376: } else {
1.1.1.25 root 13377: dma[c].ch[ch].bareg.b.l = data;
13378: }
13379: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
13380: dma[c].low_high = !dma[c].low_high;
13381: break;
13382: case 0x01: case 0x03: case 0x05: case 0x07:
13383: if(dma[c].low_high) {
13384: dma[c].ch[ch].bcreg.b.h = data;
13385: } else {
13386: dma[c].ch[ch].bcreg.b.l = data;
13387: }
13388: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
13389: dma[c].low_high = !dma[c].low_high;
13390: break;
13391: case 0x08:
13392: // command register
13393: dma[c].cmd = data;
13394: break;
13395: case 0x09:
13396: // dma[c].request register
13397: if(data & 4) {
13398: if(!(dma[c].req & bit)) {
13399: dma[c].req |= bit;
13400: // dma_run(c, ch);
13401: }
13402: } else {
13403: dma[c].req &= ~bit;
13404: }
13405: break;
13406: case 0x0a:
13407: // single mask register
13408: if(data & 4) {
13409: dma[c].mask |= bit;
13410: } else {
13411: dma[c].mask &= ~bit;
13412: }
13413: break;
13414: case 0x0b:
13415: // mode register
13416: dma[c].ch[data & 3].mode = data;
13417: break;
13418: case 0x0c:
13419: dma[c].low_high = false;
13420: break;
13421: case 0x0d:
13422: // clear master
13423: dma_reset(c);
13424: break;
13425: case 0x0e:
13426: // clear mask register
13427: dma[c].mask = 0;
13428: break;
13429: case 0x0f:
13430: // all mask register
13431: dma[c].mask = data & 0x0f;
13432: break;
13433: }
13434: }
13435:
13436: UINT8 dma_read(int c, UINT32 addr)
13437: {
13438: int ch = (addr >> 1) & 3;
13439: UINT8 val = 0xff;
13440:
13441: switch(addr & 0x0f) {
13442: case 0x00: case 0x02: case 0x04: case 0x06:
13443: if(dma[c].low_high) {
13444: val = dma[c].ch[ch].areg.b.h;
13445: } else {
13446: val = dma[c].ch[ch].areg.b.l;
13447: }
13448: dma[c].low_high = !dma[c].low_high;
13449: return(val);
13450: case 0x01: case 0x03: case 0x05: case 0x07:
13451: if(dma[c].low_high) {
13452: val = dma[c].ch[ch].creg.b.h;
13453: } else {
13454: val = dma[c].ch[ch].creg.b.l;
13455: }
13456: dma[c].low_high = !dma[c].low_high;
13457: return(val);
13458: case 0x08:
13459: // status register
13460: val = (dma[c].req << 4) | dma[c].tc;
13461: dma[c].tc = 0;
13462: return(val);
13463: case 0x0d:
1.1.1.26 root 13464: // temporary register (intel 82374 does not support)
1.1.1.25 root 13465: return(dma[c].tmp & 0xff);
1.1.1.26 root 13466: case 0x0f:
13467: // mask register (intel 82374 does support)
13468: return(dma[c].mask);
1.1.1.25 root 13469: }
13470: return(0xff);
13471: }
13472:
13473: void dma_page_write(int c, int ch, UINT8 data)
13474: {
13475: dma[c].ch[ch].pagereg = data;
13476: }
13477:
13478: UINT8 dma_page_read(int c, int ch)
13479: {
13480: return(dma[c].ch[ch].pagereg);
13481: }
13482:
13483: void dma_run(int c, int ch)
13484: {
13485: UINT8 bit = 1 << ch;
13486:
13487: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
13488: // execute dma
13489: while(dma[c].req & bit) {
13490: if(ch == 0 && (dma[c].cmd & 0x01)) {
13491: // memory -> memory
13492: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
13493: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
13494:
13495: if(c == 0) {
13496: dma[c].tmp = read_byte(saddr);
13497: write_byte(daddr, dma[c].tmp);
13498: } else {
13499: dma[c].tmp = read_word(saddr << 1);
13500: write_word(daddr << 1, dma[c].tmp);
13501: }
13502: if(!(dma[c].cmd & 0x02)) {
13503: if(dma[c].ch[0].mode & 0x20) {
13504: dma[c].ch[0].areg.w--;
13505: if(dma[c].ch[0].areg.w == 0xffff) {
13506: dma[c].ch[0].pagereg--;
13507: }
13508: } else {
13509: dma[c].ch[0].areg.w++;
13510: if(dma[c].ch[0].areg.w == 0) {
13511: dma[c].ch[0].pagereg++;
13512: }
13513: }
13514: }
13515: if(dma[c].ch[1].mode & 0x20) {
13516: dma[c].ch[1].areg.w--;
13517: if(dma[c].ch[1].areg.w == 0xffff) {
13518: dma[c].ch[1].pagereg--;
13519: }
13520: } else {
13521: dma[c].ch[1].areg.w++;
13522: if(dma[c].ch[1].areg.w == 0) {
13523: dma[c].ch[1].pagereg++;
13524: }
13525: }
13526:
13527: // check dma condition
13528: if(dma[c].ch[0].creg.w-- == 0) {
13529: if(dma[c].ch[0].mode & 0x10) {
13530: // self initialize
13531: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
13532: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
13533: } else {
13534: // dma[c].mask |= bit;
13535: }
13536: }
13537: if(dma[c].ch[1].creg.w-- == 0) {
13538: // terminal count
13539: if(dma[c].ch[1].mode & 0x10) {
13540: // self initialize
13541: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
13542: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
13543: } else {
13544: dma[c].mask |= bit;
13545: }
13546: dma[c].req &= ~bit;
13547: dma[c].tc |= bit;
13548: }
13549: } else {
13550: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
13551:
13552: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
13553: // verify
13554: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
13555: // io -> memory
13556: if(c == 0) {
13557: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
13558: write_byte(addr, dma[c].tmp);
13559: } else {
13560: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
13561: write_word(addr << 1, dma[c].tmp);
13562: }
13563: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
13564: // memory -> io
13565: if(c == 0) {
13566: dma[c].tmp = read_byte(addr);
13567: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
13568: } else {
13569: dma[c].tmp = read_word(addr << 1);
13570: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
13571: }
13572: }
13573: if(dma[c].ch[ch].mode & 0x20) {
13574: dma[c].ch[ch].areg.w--;
13575: if(dma[c].ch[ch].areg.w == 0xffff) {
13576: dma[c].ch[ch].pagereg--;
13577: }
13578: } else {
13579: dma[c].ch[ch].areg.w++;
13580: if(dma[c].ch[ch].areg.w == 0) {
13581: dma[c].ch[ch].pagereg++;
13582: }
13583: }
13584:
13585: // check dma condition
13586: if(dma[c].ch[ch].creg.w-- == 0) {
13587: // terminal count
13588: if(dma[c].ch[ch].mode & 0x10) {
13589: // self initialize
13590: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
13591: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
13592: } else {
13593: dma[c].mask |= bit;
13594: }
13595: dma[c].req &= ~bit;
13596: dma[c].tc |= bit;
13597: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
13598: // single mode
13599: break;
13600: }
13601: }
13602: }
13603: }
13604: }
13605:
13606: // pic
13607:
13608: void pic_init()
13609: {
13610: memset(pic, 0, sizeof(pic));
13611: pic[0].imr = pic[1].imr = 0xff;
13612:
13613: // from bochs bios
13614: pic_write(0, 0, 0x11); // icw1 = 11h
13615: pic_write(0, 1, 0x08); // icw2 = 08h
13616: pic_write(0, 1, 0x04); // icw3 = 04h
13617: pic_write(0, 1, 0x01); // icw4 = 01h
13618: pic_write(0, 1, 0xb8); // ocw1 = b8h
13619: pic_write(1, 0, 0x11); // icw1 = 11h
13620: pic_write(1, 1, 0x70); // icw2 = 70h
13621: pic_write(1, 1, 0x02); // icw3 = 02h
13622: pic_write(1, 1, 0x01); // icw4 = 01h
13623: }
13624:
13625: void pic_write(int c, UINT32 addr, UINT8 data)
13626: {
13627: if(addr & 1) {
13628: if(pic[c].icw2_r) {
13629: // icw2
13630: pic[c].icw2 = data;
13631: pic[c].icw2_r = 0;
13632: } else if(pic[c].icw3_r) {
13633: // icw3
13634: pic[c].icw3 = data;
13635: pic[c].icw3_r = 0;
13636: } else if(pic[c].icw4_r) {
13637: // icw4
13638: pic[c].icw4 = data;
13639: pic[c].icw4_r = 0;
13640: } else {
13641: // ocw1
1.1 root 13642: pic[c].imr = data;
13643: }
13644: } else {
13645: if(data & 0x10) {
13646: // icw1
13647: pic[c].icw1 = data;
13648: pic[c].icw2_r = 1;
13649: pic[c].icw3_r = (data & 2) ? 0 : 1;
13650: pic[c].icw4_r = data & 1;
13651: pic[c].irr = 0;
13652: pic[c].isr = 0;
13653: pic[c].imr = 0;
13654: pic[c].prio = 0;
13655: if(!(pic[c].icw1 & 1)) {
13656: pic[c].icw4 = 0;
13657: }
13658: pic[c].ocw3 = 0;
13659: } else if(data & 8) {
13660: // ocw3
13661: if(!(data & 2)) {
13662: data = (data & ~1) | (pic[c].ocw3 & 1);
13663: }
13664: if(!(data & 0x40)) {
13665: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
13666: }
13667: pic[c].ocw3 = data;
13668: } else {
13669: // ocw2
13670: int level = 0;
13671: if(data & 0x40) {
13672: level = data & 7;
13673: } else {
13674: if(!pic[c].isr) {
13675: return;
13676: }
13677: level = pic[c].prio;
13678: while(!(pic[c].isr & (1 << level))) {
13679: level = (level + 1) & 7;
13680: }
13681: }
13682: if(data & 0x80) {
13683: pic[c].prio = (level + 1) & 7;
13684: }
13685: if(data & 0x20) {
13686: pic[c].isr &= ~(1 << level);
13687: }
13688: }
13689: }
13690: pic_update();
13691: }
13692:
13693: UINT8 pic_read(int c, UINT32 addr)
13694: {
13695: if(addr & 1) {
13696: return(pic[c].imr);
13697: } else {
13698: // polling mode is not supported...
13699: //if(pic[c].ocw3 & 4) {
13700: // return ???;
13701: //}
13702: if(pic[c].ocw3 & 1) {
13703: return(pic[c].isr);
13704: } else {
13705: return(pic[c].irr);
13706: }
13707: }
13708: }
13709:
13710: void pic_req(int c, int level, int signal)
13711: {
13712: if(signal) {
13713: pic[c].irr |= (1 << level);
13714: } else {
13715: pic[c].irr &= ~(1 << level);
13716: }
13717: pic_update();
13718: }
13719:
13720: int pic_ack()
13721: {
13722: // ack (INTA=L)
13723: pic[pic_req_chip].isr |= pic_req_bit;
13724: pic[pic_req_chip].irr &= ~pic_req_bit;
13725: if(pic_req_chip > 0) {
13726: // update isr and irr of master
13727: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
13728: pic[pic_req_chip - 1].isr |= slave;
13729: pic[pic_req_chip - 1].irr &= ~slave;
13730: }
13731: //if(pic[pic_req_chip].icw4 & 1) {
13732: // 8086 mode
13733: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
13734: //} else {
13735: // // 8080 mode
13736: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
13737: // if(pic[pic_req_chip].icw1 & 4) {
13738: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
13739: // } else {
13740: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
13741: // }
13742: // vector = 0xcd | (addr << 8);
13743: //}
13744: if(pic[pic_req_chip].icw4 & 2) {
13745: // auto eoi
13746: pic[pic_req_chip].isr &= ~pic_req_bit;
13747: }
13748: return(vector);
13749: }
13750:
13751: void pic_update()
13752: {
13753: for(int c = 0; c < 2; c++) {
13754: UINT8 irr = pic[c].irr;
13755: if(c + 1 < 2) {
13756: // this is master
13757: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
13758: // request from slave
13759: irr |= 1 << (pic[c + 1].icw3 & 7);
13760: }
13761: }
13762: irr &= (~pic[c].imr);
13763: if(!irr) {
13764: break;
13765: }
13766: if(!(pic[c].ocw3 & 0x20)) {
13767: irr |= pic[c].isr;
13768: }
13769: int level = pic[c].prio;
13770: UINT8 bit = 1 << level;
13771: while(!(irr & bit)) {
13772: level = (level + 1) & 7;
13773: bit = 1 << level;
13774: }
13775: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
13776: // check slave
13777: continue;
13778: }
13779: if(pic[c].isr & bit) {
13780: break;
13781: }
13782: // interrupt request
13783: pic_req_chip = c;
13784: pic_req_level = level;
13785: pic_req_bit = bit;
1.1.1.3 root 13786: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 13787: return;
13788: }
1.1.1.3 root 13789: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 13790: }
1.1 root 13791:
1.1.1.25 root 13792: // pio
13793:
13794: void pio_init()
13795: {
1.1.1.26 root 13796: memset(pio, 0, sizeof(pio));
1.1.1.25 root 13797: for(int c = 0; c < 2; c++) {
13798: pio[c].stat = 0xde;
13799: pio[c].ctrl = 0x0c;
13800: }
13801: }
13802:
13803: void pio_write(int c, UINT32 addr, UINT8 data)
13804: {
13805: switch(addr & 3) {
13806: case 0:
13807: pio[c].data = data;
13808: break;
13809: case 2:
13810: pio[c].ctrl = data;
13811: break;
13812: }
13813: }
13814:
13815: UINT8 pio_read(int c, UINT32 addr)
13816: {
13817: switch(addr & 3) {
13818: case 0:
13819: return(pio[c].data);
13820: case 1:
13821: return(pio[c].stat);
13822: case 2:
13823: return(pio[c].ctrl);
13824: }
13825: return(0xff);
13826: }
13827:
1.1 root 13828: // pit
13829:
1.1.1.22 root 13830: #define PIT_FREQ 1193182ULL
1.1 root 13831: #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)
13832:
13833: void pit_init()
13834: {
1.1.1.8 root 13835: memset(pit, 0, sizeof(pit));
1.1 root 13836: for(int ch = 0; ch < 3; ch++) {
13837: pit[ch].count = 0x10000;
13838: pit[ch].ctrl_reg = 0x34;
13839: pit[ch].mode = 3;
13840: }
13841:
13842: // from bochs bios
13843: pit_write(3, 0x34);
13844: pit_write(0, 0x00);
13845: pit_write(0, 0x00);
13846: }
13847:
13848: void pit_write(int ch, UINT8 val)
13849: {
1.1.1.8 root 13850: #ifndef PIT_ALWAYS_RUNNING
1.1 root 13851: if(!pit_active) {
13852: pit_active = 1;
13853: pit_init();
13854: }
1.1.1.8 root 13855: #endif
1.1 root 13856: switch(ch) {
13857: case 0:
13858: case 1:
13859: case 2:
13860: // write count register
13861: if(!pit[ch].low_write && !pit[ch].high_write) {
13862: if(pit[ch].ctrl_reg & 0x10) {
13863: pit[ch].low_write = 1;
13864: }
13865: if(pit[ch].ctrl_reg & 0x20) {
13866: pit[ch].high_write = 1;
13867: }
13868: }
13869: if(pit[ch].low_write) {
13870: pit[ch].count_reg = val;
13871: pit[ch].low_write = 0;
13872: } else if(pit[ch].high_write) {
13873: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
13874: pit[ch].count_reg = val << 8;
13875: } else {
13876: pit[ch].count_reg |= val << 8;
13877: }
13878: pit[ch].high_write = 0;
13879: }
13880: // start count
1.1.1.8 root 13881: if(!pit[ch].low_write && !pit[ch].high_write) {
13882: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
13883: pit[ch].count = PIT_COUNT_VALUE(ch);
13884: pit[ch].prev_time = timeGetTime();
13885: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 13886: }
13887: }
13888: break;
13889: case 3: // ctrl reg
13890: if((val & 0xc0) == 0xc0) {
13891: // i8254 read-back command
13892: for(ch = 0; ch < 3; ch++) {
13893: if(!(val & 0x10) && !pit[ch].status_latched) {
13894: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
13895: pit[ch].status_latched = 1;
13896: }
13897: if(!(val & 0x20) && !pit[ch].count_latched) {
13898: pit_latch_count(ch);
13899: }
13900: }
13901: break;
13902: }
13903: ch = (val >> 6) & 3;
13904: if(val & 0x30) {
13905: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
13906: pit[ch].mode = modes[(val >> 1) & 7];
13907: pit[ch].count_latched = 0;
13908: pit[ch].low_read = pit[ch].high_read = 0;
13909: pit[ch].low_write = pit[ch].high_write = 0;
13910: pit[ch].ctrl_reg = val;
13911: // stop count
1.1.1.8 root 13912: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 13913: pit[ch].count_reg = 0;
13914: } else if(!pit[ch].count_latched) {
13915: pit_latch_count(ch);
13916: }
13917: break;
13918: }
13919: }
13920:
13921: UINT8 pit_read(int ch)
13922: {
1.1.1.8 root 13923: #ifndef PIT_ALWAYS_RUNNING
1.1 root 13924: if(!pit_active) {
13925: pit_active = 1;
13926: pit_init();
13927: }
1.1.1.8 root 13928: #endif
1.1 root 13929: switch(ch) {
13930: case 0:
13931: case 1:
13932: case 2:
13933: if(pit[ch].status_latched) {
13934: pit[ch].status_latched = 0;
13935: return(pit[ch].status);
13936: }
13937: // if not latched, through current count
13938: if(!pit[ch].count_latched) {
13939: if(!pit[ch].low_read && !pit[ch].high_read) {
13940: pit_latch_count(ch);
13941: }
13942: }
13943: // return latched count
13944: if(pit[ch].low_read) {
13945: pit[ch].low_read = 0;
13946: if(!pit[ch].high_read) {
13947: pit[ch].count_latched = 0;
13948: }
13949: return(pit[ch].latch & 0xff);
13950: } else if(pit[ch].high_read) {
13951: pit[ch].high_read = 0;
13952: pit[ch].count_latched = 0;
13953: return((pit[ch].latch >> 8) & 0xff);
13954: }
13955: }
13956: return(0xff);
13957: }
13958:
1.1.1.8 root 13959: int pit_run(int ch, UINT32 cur_time)
1.1 root 13960: {
1.1.1.8 root 13961: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 13962: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 13963: pit[ch].prev_time = pit[ch].expired_time;
13964: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
13965: if(cur_time >= pit[ch].expired_time) {
13966: pit[ch].prev_time = cur_time;
13967: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 13968: }
1.1.1.8 root 13969: return(1);
1.1 root 13970: }
1.1.1.8 root 13971: return(0);
1.1 root 13972: }
13973:
13974: void pit_latch_count(int ch)
13975: {
1.1.1.8 root 13976: if(pit[ch].expired_time != 0) {
1.1.1.26 root 13977: UINT32 cur_time = timeGetTime();
1.1.1.8 root 13978: pit_run(ch, cur_time);
13979: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 13980: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
13981:
13982: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
13983: // decrement counter in 1msec period
13984: if(pit[ch].next_latch == 0) {
13985: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
13986: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
13987: }
13988: if(pit[ch].latch > pit[ch].next_latch) {
13989: pit[ch].latch--;
13990: }
13991: } else {
13992: pit[ch].prev_latch = pit[ch].latch = latch;
13993: pit[ch].next_latch = 0;
13994: }
1.1.1.8 root 13995: } else {
13996: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 13997: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 13998: }
13999: pit[ch].count_latched = 1;
14000: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
14001: // lower byte
14002: pit[ch].low_read = 1;
14003: pit[ch].high_read = 0;
14004: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
14005: // upper byte
14006: pit[ch].low_read = 0;
14007: pit[ch].high_read = 1;
14008: } else {
14009: // lower -> upper
1.1.1.14 root 14010: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 14011: }
14012: }
14013:
1.1.1.8 root 14014: int pit_get_expired_time(int ch)
1.1 root 14015: {
1.1.1.22 root 14016: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
14017: UINT64 val = pit[ch].accum >> 10;
14018: pit[ch].accum -= val << 10;
14019: return((val != 0) ? val : 1);
1.1.1.8 root 14020: }
14021:
1.1.1.25 root 14022: // sio
14023:
14024: void sio_init()
14025: {
1.1.1.26 root 14026: memset(sio, 0, sizeof(sio));
14027: memset(sio_mt, 0, sizeof(sio_mt));
14028:
1.1.1.29 root 14029: for(int c = 0; c < 4; c++) {
1.1.1.25 root 14030: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
14031: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
14032:
14033: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
14034: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 14035: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
14036: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 14037: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
14038: sio[c].irq_identify = 0x01; // no pending irq
14039:
14040: InitializeCriticalSection(&sio_mt[c].csSendData);
14041: InitializeCriticalSection(&sio_mt[c].csRecvData);
14042: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
14043: InitializeCriticalSection(&sio_mt[c].csLineStat);
14044: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
14045: InitializeCriticalSection(&sio_mt[c].csModemStat);
14046:
1.1.1.26 root 14047: if(sio_port_number[c] != 0) {
1.1.1.25 root 14048: sio[c].channel = c;
14049: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
14050: }
14051: }
14052: }
14053:
14054: void sio_finish()
14055: {
1.1.1.29 root 14056: for(int c = 0; c < 4; c++) {
1.1.1.25 root 14057: if(sio_mt[c].hThread != NULL) {
14058: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
14059: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 14060: sio_mt[c].hThread = NULL;
1.1.1.25 root 14061: }
14062: DeleteCriticalSection(&sio_mt[c].csSendData);
14063: DeleteCriticalSection(&sio_mt[c].csRecvData);
14064: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
14065: DeleteCriticalSection(&sio_mt[c].csLineStat);
14066: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
14067: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 14068: }
14069: sio_release();
14070: }
14071:
14072: void sio_release()
14073: {
1.1.1.29 root 14074: for(int c = 0; c < 4; c++) {
1.1.1.28 root 14075: // sio_thread() may access the resources :-(
1.1.1.32! root 14076: bool running = (sio_mt[c].hThread != NULL);
! 14077:
! 14078: if(running) {
! 14079: EnterCriticalSection(&sio_mt[c].csSendData);
! 14080: }
! 14081: if(sio[c].send_buffer != NULL) {
! 14082: sio[c].send_buffer->release();
! 14083: delete sio[c].send_buffer;
! 14084: sio[c].send_buffer = NULL;
! 14085: }
! 14086: if(running) {
! 14087: LeaveCriticalSection(&sio_mt[c].csSendData);
! 14088: EnterCriticalSection(&sio_mt[c].csRecvData);
! 14089: }
! 14090: if(sio[c].recv_buffer != NULL) {
! 14091: sio[c].recv_buffer->release();
! 14092: delete sio[c].recv_buffer;
! 14093: sio[c].recv_buffer = NULL;
! 14094: }
! 14095: if(running) {
! 14096: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 14097: }
1.1.1.25 root 14098: }
14099: }
14100:
14101: void sio_write(int c, UINT32 addr, UINT8 data)
14102: {
14103: switch(addr & 7) {
14104: case 0:
14105: if(sio[c].selector & 0x80) {
14106: if(sio[c].divisor.b.l != data) {
14107: EnterCriticalSection(&sio_mt[c].csLineCtrl);
14108: sio[c].divisor.b.l = data;
14109: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
14110: }
14111: } else {
14112: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32! root 14113: if(sio[c].send_buffer != NULL) {
! 14114: sio[c].send_buffer->write(data);
! 14115: }
1.1.1.25 root 14116: // transmitter holding/shift registers are not empty
14117: sio[c].line_stat_buf &= ~0x60;
14118: LeaveCriticalSection(&sio_mt[c].csSendData);
14119:
14120: if(sio[c].irq_enable & 0x02) {
14121: sio_update_irq(c);
14122: }
14123: }
14124: break;
14125: case 1:
14126: if(sio[c].selector & 0x80) {
14127: if(sio[c].divisor.b.h != data) {
14128: EnterCriticalSection(&sio_mt[c].csLineCtrl);
14129: sio[c].divisor.b.h = data;
14130: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
14131: }
14132: } else {
14133: if(sio[c].irq_enable != data) {
14134: sio[c].irq_enable = data;
14135: sio_update_irq(c);
14136: }
14137: }
14138: break;
14139: case 3:
14140: {
14141: UINT8 line_ctrl = data & 0x3f;
14142: bool set_brk = ((data & 0x40) != 0);
14143:
14144: if(sio[c].line_ctrl != line_ctrl) {
14145: EnterCriticalSection(&sio_mt[c].csLineCtrl);
14146: sio[c].line_ctrl = line_ctrl;
14147: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
14148: }
14149: if(sio[c].set_brk != set_brk) {
14150: EnterCriticalSection(&sio_mt[c].csModemCtrl);
14151: sio[c].set_brk = set_brk;
14152: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
14153: }
14154: }
14155: sio[c].selector = data;
14156: break;
14157: case 4:
14158: {
14159: bool set_dtr = ((data & 0x01) != 0);
14160: bool set_rts = ((data & 0x02) != 0);
14161:
14162: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 14163: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 14164: sio[c].set_dtr = set_dtr;
14165: sio[c].set_rts = set_rts;
1.1.1.26 root 14166: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
14167:
14168: bool state_changed = false;
14169:
14170: EnterCriticalSection(&sio_mt[c].csModemStat);
14171: if(set_dtr) {
14172: sio[c].modem_stat |= 0x20; // dsr on
14173: } else {
14174: sio[c].modem_stat &= ~0x20; // dsr off
14175: }
14176: if(set_rts) {
14177: sio[c].modem_stat |= 0x10; // cts on
14178: } else {
14179: sio[c].modem_stat &= ~0x10; // cts off
14180: }
14181: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
14182: if(!(sio[c].modem_stat & 0x02)) {
14183: if(sio[c].irq_enable & 0x08) {
14184: state_changed = true;
14185: }
14186: sio[c].modem_stat |= 0x02;
14187: }
14188: }
14189: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
14190: if(!(sio[c].modem_stat & 0x01)) {
14191: if(sio[c].irq_enable & 0x08) {
14192: state_changed = true;
14193: }
14194: sio[c].modem_stat |= 0x01;
14195: }
14196: }
14197: LeaveCriticalSection(&sio_mt[c].csModemStat);
14198:
14199: if(state_changed) {
14200: sio_update_irq(c);
14201: }
1.1.1.25 root 14202: }
14203: }
14204: sio[c].modem_ctrl = data;
14205: break;
14206: case 7:
14207: sio[c].scratch = data;
14208: break;
14209: }
14210: }
14211:
14212: UINT8 sio_read(int c, UINT32 addr)
14213: {
14214: switch(addr & 7) {
14215: case 0:
14216: if(sio[c].selector & 0x80) {
14217: return(sio[c].divisor.b.l);
14218: } else {
14219: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32! root 14220: UINT8 data = 0;
! 14221: if(sio[c].recv_buffer != NULL) {
! 14222: data = sio[c].recv_buffer->read();
! 14223: }
1.1.1.25 root 14224: // data is not ready
14225: sio[c].line_stat_buf &= ~0x01;
14226: LeaveCriticalSection(&sio_mt[c].csRecvData);
14227:
14228: if(sio[c].irq_enable & 0x01) {
14229: sio_update_irq(c);
14230: }
14231: return(data);
14232: }
14233: case 1:
14234: if(sio[c].selector & 0x80) {
14235: return(sio[c].divisor.b.h);
14236: } else {
14237: return(sio[c].irq_enable);
14238: }
14239: case 2:
14240: return(sio[c].irq_identify);
14241: case 3:
14242: return(sio[c].selector);
14243: case 4:
14244: return(sio[c].modem_ctrl);
14245: case 5:
14246: {
14247: EnterCriticalSection(&sio_mt[c].csLineStat);
14248: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
14249: sio[c].line_stat_err = 0x00;
14250: LeaveCriticalSection(&sio_mt[c].csLineStat);
14251:
14252: bool state_changed = false;
14253:
14254: if((sio[c].line_stat_buf & 0x60) == 0x00) {
14255: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32! root 14256: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 14257: // transmitter holding register will be empty first
14258: if(sio[c].irq_enable & 0x02) {
14259: state_changed = true;
14260: }
14261: sio[c].line_stat_buf |= 0x20;
14262: }
14263: LeaveCriticalSection(&sio_mt[c].csSendData);
14264: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
14265: // transmitter shift register will be empty later
14266: sio[c].line_stat_buf |= 0x40;
14267: }
14268: if(!(sio[c].line_stat_buf & 0x01)) {
14269: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32! root 14270: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 14271: // data is ready
14272: if(sio[c].irq_enable & 0x01) {
14273: state_changed = true;
14274: }
14275: sio[c].line_stat_buf |= 0x01;
14276: }
14277: LeaveCriticalSection(&sio_mt[c].csRecvData);
14278: }
14279: if(state_changed) {
14280: sio_update_irq(c);
14281: }
14282: return(val);
14283: }
14284: case 6:
14285: {
14286: EnterCriticalSection(&sio_mt[c].csModemStat);
14287: UINT8 val = sio[c].modem_stat;
14288: sio[c].modem_stat &= 0xf0;
14289: sio[c].prev_modem_stat = sio[c].modem_stat;
14290: LeaveCriticalSection(&sio_mt[c].csModemStat);
14291:
14292: if(sio[c].modem_ctrl & 0x10) {
14293: // loop-back
14294: val &= 0x0f;
14295: val |= (sio[c].modem_ctrl & 0x0c) << 4;
14296: val |= (sio[c].modem_ctrl & 0x01) << 5;
14297: val |= (sio[c].modem_ctrl & 0x02) << 3;
14298: }
14299: return(val);
14300: }
14301: case 7:
14302: return(sio[c].scratch);
14303: }
14304: return(0xff);
14305: }
14306:
14307: void sio_update(int c)
14308: {
14309: if((sio[c].line_stat_buf & 0x60) == 0x00) {
14310: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32! root 14311: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 14312: // transmitter holding/shift registers will be empty
14313: sio[c].line_stat_buf |= 0x60;
14314: }
14315: LeaveCriticalSection(&sio_mt[c].csSendData);
14316: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
14317: // transmitter shift register will be empty
14318: sio[c].line_stat_buf |= 0x40;
14319: }
14320: if(!(sio[c].line_stat_buf & 0x01)) {
14321: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32! root 14322: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 14323: // data is ready
14324: sio[c].line_stat_buf |= 0x01;
14325: }
14326: LeaveCriticalSection(&sio_mt[c].csRecvData);
14327: }
14328: sio_update_irq(c);
14329: }
14330:
14331: void sio_update_irq(int c)
14332: {
14333: int level = -1;
14334:
14335: if(sio[c].irq_enable & 0x08) {
14336: EnterCriticalSection(&sio_mt[c].csModemStat);
14337: if((sio[c].modem_stat & 0x0f) != 0) {
14338: level = 0;
14339: }
14340: EnterCriticalSection(&sio_mt[c].csModemStat);
14341: }
14342: if(sio[c].irq_enable & 0x02) {
14343: if(sio[c].line_stat_buf & 0x20) {
14344: level = 1;
14345: }
14346: }
14347: if(sio[c].irq_enable & 0x01) {
14348: if(sio[c].line_stat_buf & 0x01) {
14349: level = 2;
14350: }
14351: }
14352: if(sio[c].irq_enable & 0x04) {
14353: EnterCriticalSection(&sio_mt[c].csLineStat);
14354: if(sio[c].line_stat_err != 0) {
14355: level = 3;
14356: }
14357: LeaveCriticalSection(&sio_mt[c].csLineStat);
14358: }
1.1.1.29 root 14359:
14360: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 14361: if(level != -1) {
14362: sio[c].irq_identify = level << 1;
1.1.1.29 root 14363: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 14364: } else {
14365: sio[c].irq_identify = 1;
1.1.1.29 root 14366: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 14367: }
14368: }
14369:
14370: DWORD WINAPI sio_thread(void *lpx)
14371: {
14372: volatile sio_t *p = (sio_t *)lpx;
14373: sio_mt_t *q = &sio_mt[p->channel];
14374:
14375: char name[] = "COM1";
1.1.1.26 root 14376: name[3] = '0' + sio_port_number[p->channel];
14377: HANDLE hComm = NULL;
14378: COMMPROP commProp;
14379: DCB dcb;
14380: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
14381: BYTE bytBuffer[SIO_BUFFER_SIZE];
14382:
14383: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
14384: if(GetCommProperties(hComm, &commProp)) {
14385: dwSettableBaud = commProp.dwSettableBaud;
14386: }
1.1.1.25 root 14387: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 14388: // EscapeCommFunction(hComm, SETRTS);
14389: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 14390:
14391: while(!m_halted) {
14392: // setup comm port
14393: bool comm_state_changed = false;
14394:
14395: EnterCriticalSection(&q->csLineCtrl);
14396: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
14397: p->prev_divisor = p->divisor.w;
14398: p->prev_line_ctrl = p->line_ctrl;
14399: comm_state_changed = true;
14400: }
14401: LeaveCriticalSection(&q->csLineCtrl);
14402:
14403: if(comm_state_changed) {
1.1.1.26 root 14404: if(GetCommState(hComm, &dcb)) {
14405: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
14406: DWORD baud = 115200 / p->prev_divisor;
14407: dcb.BaudRate = 9600; // default
14408:
14409: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
14410: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
14411: // 134.5bps is not supported ???
14412: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
14413: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
14414: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
14415: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
14416: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
14417: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
14418: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
14419: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
14420: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
14421: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
14422: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
14423: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
14424: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
14425:
14426: switch(p->prev_line_ctrl & 0x03) {
14427: case 0x00: dcb.ByteSize = 5; break;
14428: case 0x01: dcb.ByteSize = 6; break;
14429: case 0x02: dcb.ByteSize = 7; break;
14430: case 0x03: dcb.ByteSize = 8; break;
14431: }
14432: switch(p->prev_line_ctrl & 0x04) {
14433: case 0x00: dcb.StopBits = ONESTOPBIT; break;
14434: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
14435: }
14436: switch(p->prev_line_ctrl & 0x38) {
14437: case 0x08: dcb.Parity = ODDPARITY; break;
14438: case 0x18: dcb.Parity = EVENPARITY; break;
14439: case 0x28: dcb.Parity = MARKPARITY; break;
14440: case 0x38: dcb.Parity = SPACEPARITY; break;
14441: default: dcb.Parity = NOPARITY; break;
14442: }
14443: dcb.fBinary = TRUE;
14444: dcb.fParity = (dcb.Parity != NOPARITY);
14445: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
14446: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
14447: dcb.fDsrSensitivity = FALSE;//TRUE;
14448: dcb.fTXContinueOnXoff = TRUE;
14449: dcb.fOutX = dcb.fInX = FALSE;
14450: dcb.fErrorChar = FALSE;
14451: dcb.fNull = FALSE;
14452: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
14453: dcb.fAbortOnError = FALSE;
14454:
14455: SetCommState(hComm, &dcb);
1.1.1.25 root 14456: }
14457:
14458: // check again to apply all comm state changes
14459: Sleep(10);
14460: continue;
14461: }
14462:
14463: // set comm pins
14464: bool change_brk = false;
1.1.1.26 root 14465: // bool change_rts = false;
14466: // bool change_dtr = false;
1.1.1.25 root 14467:
14468: EnterCriticalSection(&q->csModemCtrl);
14469: if(p->prev_set_brk != p->set_brk) {
14470: p->prev_set_brk = p->set_brk;
14471: change_brk = true;
14472: }
1.1.1.26 root 14473: // if(p->prev_set_rts != p->set_rts) {
14474: // p->prev_set_rts = p->set_rts;
14475: // change_rts = true;
14476: // }
14477: // if(p->prev_set_dtr != p->set_dtr) {
14478: // p->prev_set_dtr = p->set_dtr;
14479: // change_dtr = true;
14480: // }
1.1.1.25 root 14481: LeaveCriticalSection(&q->csModemCtrl);
14482:
14483: if(change_brk) {
1.1.1.26 root 14484: static UINT32 clear_time = 0;
14485: if(p->prev_set_brk) {
14486: EscapeCommFunction(hComm, SETBREAK);
14487: clear_time = timeGetTime() + 200;
14488: } else {
14489: // keep break for at least 200msec
14490: UINT32 cur_time = timeGetTime();
14491: if(clear_time > cur_time) {
14492: Sleep(clear_time - cur_time);
14493: }
14494: EscapeCommFunction(hComm, CLRBREAK);
14495: }
1.1.1.25 root 14496: }
1.1.1.26 root 14497: // if(change_rts) {
14498: // if(p->prev_set_rts) {
14499: // EscapeCommFunction(hComm, SETRTS);
14500: // } else {
14501: // EscapeCommFunction(hComm, CLRRTS);
14502: // }
14503: // }
14504: // if(change_dtr) {
14505: // if(p->prev_set_dtr) {
14506: // EscapeCommFunction(hComm, SETDTR);
14507: // } else {
14508: // EscapeCommFunction(hComm, CLRDTR);
14509: // }
14510: // }
1.1.1.25 root 14511:
14512: // get comm pins
14513: DWORD dwModemStat = 0;
14514:
14515: if(GetCommModemStatus(hComm, &dwModemStat)) {
14516: EnterCriticalSection(&q->csModemStat);
14517: if(dwModemStat & MS_RLSD_ON) {
14518: p->modem_stat |= 0x80;
14519: } else {
14520: p->modem_stat &= ~0x80;
14521: }
14522: if(dwModemStat & MS_RING_ON) {
14523: p->modem_stat |= 0x40;
14524: } else {
14525: p->modem_stat &= ~0x40;
14526: }
1.1.1.26 root 14527: // if(dwModemStat & MS_DSR_ON) {
14528: // p->modem_stat |= 0x20;
14529: // } else {
14530: // p->modem_stat &= ~0x20;
14531: // }
14532: // if(dwModemStat & MS_CTS_ON) {
14533: // p->modem_stat |= 0x10;
14534: // } else {
14535: // p->modem_stat &= ~0x10;
14536: // }
1.1.1.25 root 14537: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
14538: p->modem_stat |= 0x08;
14539: }
14540: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
14541: p->modem_stat |= 0x04;
14542: }
1.1.1.26 root 14543: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
14544: // p->modem_stat |= 0x02;
14545: // }
14546: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
14547: // p->modem_stat |= 0x01;
14548: // }
1.1.1.25 root 14549: LeaveCriticalSection(&q->csModemStat);
14550: }
14551:
14552: // send data
14553: DWORD dwSend = 0;
14554:
14555: EnterCriticalSection(&q->csSendData);
1.1.1.32! root 14556: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 14557: bytBuffer[dwSend++] = p->send_buffer->read();
14558: }
14559: LeaveCriticalSection(&q->csSendData);
14560:
14561: if(dwSend != 0) {
14562: DWORD dwWritten = 0;
14563: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
14564: }
14565:
14566: // get line status and recv data
14567: DWORD dwLineStat = 0;
14568: COMSTAT comStat;
14569:
14570: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
14571: EnterCriticalSection(&q->csLineStat);
14572: if(dwLineStat & CE_BREAK) {
14573: p->line_stat_err |= 0x10;
14574: }
14575: if(dwLineStat & CE_FRAME) {
14576: p->line_stat_err |= 0x08;
14577: }
14578: if(dwLineStat & CE_RXPARITY) {
14579: p->line_stat_err |= 0x04;
14580: }
14581: if(dwLineStat & CE_OVERRUN) {
14582: p->line_stat_err |= 0x02;
14583: }
14584: LeaveCriticalSection(&q->csLineStat);
14585:
14586: if(comStat.cbInQue != 0) {
14587: EnterCriticalSection(&q->csRecvData);
1.1.1.32! root 14588: DWORD dwRecv = 0;
! 14589: if(p->recv_buffer != NULL) {
! 14590: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
! 14591: }
1.1.1.25 root 14592: LeaveCriticalSection(&q->csRecvData);
14593:
14594: if(dwRecv != 0) {
14595: DWORD dwRead = 0;
14596: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
14597: EnterCriticalSection(&q->csRecvData);
1.1.1.32! root 14598: if(p->recv_buffer != NULL) {
! 14599: for(int i = 0; i < dwRead; i++) {
! 14600: p->recv_buffer->write(bytBuffer[i]);
! 14601: }
1.1.1.25 root 14602: }
14603: LeaveCriticalSection(&q->csRecvData);
14604: }
14605: }
14606: }
14607: }
14608: Sleep(10);
14609: }
14610: CloseHandle(hComm);
14611: }
14612: return 0;
14613: }
14614:
1.1.1.8 root 14615: // cmos
14616:
14617: void cmos_init()
14618: {
14619: memset(cmos, 0, sizeof(cmos));
14620: cmos_addr = 0;
1.1 root 14621:
1.1.1.8 root 14622: // from DOSBox
14623: cmos_write(0x0a, 0x26);
14624: cmos_write(0x0b, 0x02);
14625: cmos_write(0x0d, 0x80);
1.1 root 14626: }
14627:
1.1.1.8 root 14628: void cmos_write(int addr, UINT8 val)
1.1 root 14629: {
1.1.1.8 root 14630: cmos[addr & 0x7f] = val;
14631: }
14632:
14633: #define CMOS_GET_TIME() { \
14634: UINT32 cur_sec = timeGetTime() / 1000 ; \
14635: if(prev_sec != cur_sec) { \
14636: GetLocalTime(&time); \
14637: prev_sec = cur_sec; \
14638: } \
1.1 root 14639: }
1.1.1.8 root 14640: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 14641:
1.1.1.8 root 14642: UINT8 cmos_read(int addr)
1.1 root 14643: {
1.1.1.8 root 14644: static SYSTEMTIME time;
14645: static UINT32 prev_sec = 0;
1.1 root 14646:
1.1.1.8 root 14647: switch(addr & 0x7f) {
14648: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
14649: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
14650: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
14651: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
14652: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
14653: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
14654: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
14655: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
14656: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
14657: case 0x15: return((MEMORY_END >> 10) & 0xff);
14658: case 0x16: return((MEMORY_END >> 18) & 0xff);
14659: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
14660: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
14661: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
14662: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
14663: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 14664: }
1.1.1.8 root 14665: return(cmos[addr & 0x7f]);
1.1 root 14666: }
14667:
1.1.1.7 root 14668: // kbd (a20)
14669:
14670: void kbd_init()
14671: {
1.1.1.8 root 14672: kbd_data = kbd_command = 0;
1.1.1.7 root 14673: kbd_status = 0x18;
14674: }
14675:
14676: UINT8 kbd_read_data()
14677: {
1.1.1.8 root 14678: kbd_status &= ~1;
1.1.1.7 root 14679: return(kbd_data);
14680: }
14681:
14682: void kbd_write_data(UINT8 val)
14683: {
14684: switch(kbd_command) {
14685: case 0xd1:
14686: i386_set_a20_line((val >> 1) & 1);
14687: break;
14688: }
14689: kbd_command = 0;
1.1.1.8 root 14690: kbd_status &= ~8;
1.1.1.7 root 14691: }
14692:
14693: UINT8 kbd_read_status()
14694: {
14695: return(kbd_status);
14696: }
14697:
14698: void kbd_write_command(UINT8 val)
14699: {
14700: switch(val) {
14701: case 0xd0:
14702: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 14703: kbd_status |= 1;
1.1.1.7 root 14704: break;
14705: case 0xdd:
14706: i386_set_a20_line(0);
14707: break;
14708: case 0xdf:
14709: i386_set_a20_line(1);
14710: break;
1.1.1.26 root 14711: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
14712: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 14713: if(!(val & 1)) {
1.1.1.8 root 14714: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 14715: // reset pic
14716: pic_init();
14717: pic[0].irr = pic[1].irr = 0x00;
14718: pic[0].imr = pic[1].imr = 0xff;
14719: }
14720: CPU_RESET_CALL(CPU_MODEL);
14721: i386_jmp_far(0x40, 0x67);
14722: }
14723: i386_set_a20_line((val >> 1) & 1);
14724: break;
14725: }
14726: kbd_command = val;
1.1.1.8 root 14727: kbd_status |= 8;
1.1.1.7 root 14728: }
14729:
1.1.1.9 root 14730: // vga
14731:
14732: UINT8 vga_read_status()
14733: {
14734: // 60hz
14735: static const int period[3] = {16, 17, 17};
14736: static int index = 0;
14737: UINT32 time = timeGetTime() % period[index];
14738:
14739: index = (index + 1) % 3;
1.1.1.14 root 14740: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 14741: }
14742:
1.1 root 14743: // i/o bus
14744:
1.1.1.29 root 14745: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
14746: //#define SW1US_PATCH
14747:
1.1.1.25 root 14748: #ifdef ENABLE_DEBUG_IOPORT
14749: UINT8 read_io_byte_debug(offs_t addr);
14750:
14751: UINT8 read_io_byte(offs_t addr)
14752: {
14753: UINT8 val = read_io_byte_debug(addr);
14754: if(fdebug != NULL) {
14755: fprintf(fdebug, "inb %04X, %02X\n", addr, val);
14756: }
14757: return(val);
14758: }
14759:
14760: UINT8 read_io_byte_debug(offs_t addr)
14761: #else
1.1 root 14762: UINT8 read_io_byte(offs_t addr)
1.1.1.25 root 14763: #endif
1.1 root 14764: {
14765: switch(addr) {
1.1.1.29 root 14766: #ifdef SW1US_PATCH
14767: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
14768: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
14769: return(sio_read(0, addr - 1));
14770: #else
1.1.1.25 root 14771: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
14772: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
14773: return(dma_read(0, addr));
1.1.1.29 root 14774: #endif
1.1.1.25 root 14775: case 0x20: case 0x21:
1.1 root 14776: return(pic_read(0, addr));
1.1.1.25 root 14777: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 14778: return(pit_read(addr & 0x03));
1.1.1.7 root 14779: case 0x60:
14780: return(kbd_read_data());
1.1.1.9 root 14781: case 0x61:
14782: return(system_port);
1.1.1.7 root 14783: case 0x64:
14784: return(kbd_read_status());
1.1 root 14785: case 0x71:
1.1.1.8 root 14786: return(cmos_read(cmos_addr));
1.1.1.25 root 14787: case 0x81:
14788: return(dma_page_read(0, 2));
14789: case 0x82:
14790: return(dma_page_read(0, 3));
14791: case 0x83:
14792: return(dma_page_read(0, 1));
14793: case 0x87:
14794: return(dma_page_read(0, 0));
14795: case 0x89:
14796: return(dma_page_read(1, 2));
14797: case 0x8a:
14798: return(dma_page_read(1, 3));
14799: case 0x8b:
14800: return(dma_page_read(1, 1));
14801: case 0x8f:
14802: return(dma_page_read(1, 0));
1.1 root 14803: case 0x92:
1.1.1.3 root 14804: return((m_a20_mask >> 19) & 2);
1.1.1.25 root 14805: case 0xa0: case 0xa1:
1.1 root 14806: return(pic_read(1, addr));
1.1.1.25 root 14807: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
14808: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 14809: return(dma_read(1, (addr - 0xc0) >> 1));
14810: // case 0x278: case 0x279: case 0x27a:
14811: // return(pio_read(1, addr));
1.1.1.29 root 14812: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
14813: return(sio_read(3, addr));
1.1.1.25 root 14814: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
14815: return(sio_read(1, addr));
14816: case 0x378: case 0x379: case 0x37a:
14817: return(pio_read(0, addr));
14818: case 0x3ba: case 0x3da:
1.1.1.9 root 14819: return(vga_read_status());
1.1.1.29 root 14820: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
14821: return(sio_read(2, addr));
1.1.1.25 root 14822: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
14823: return(sio_read(0, addr));
1.1 root 14824: default:
14825: // error("inb %4x\n", addr);
14826: break;
14827: }
14828: return(0xff);
14829: }
14830:
14831: UINT16 read_io_word(offs_t addr)
14832: {
14833: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
14834: }
14835:
14836: UINT32 read_io_dword(offs_t addr)
14837: {
14838: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
14839: }
14840:
14841: void write_io_byte(offs_t addr, UINT8 val)
14842: {
1.1.1.25 root 14843: #ifdef ENABLE_DEBUG_IOPORT
14844: if(fdebug != NULL) {
14845: fprintf(fdebug, "outb %04X, %02X\n", addr, val);
14846: }
14847: #endif
1.1 root 14848: switch(addr) {
1.1.1.29 root 14849: #ifdef SW1US_PATCH
14850: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
14851: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
14852: sio_write(0, addr - 1, val);
14853: break;
14854: #else
1.1.1.25 root 14855: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
14856: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
14857: dma_write(0, addr, val);
14858: break;
1.1.1.29 root 14859: #endif
1.1.1.25 root 14860: case 0x20: case 0x21:
1.1 root 14861: pic_write(0, addr, val);
14862: break;
1.1.1.25 root 14863: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 14864: pit_write(addr & 0x03, val);
14865: break;
1.1.1.7 root 14866: case 0x60:
14867: kbd_write_data(val);
14868: break;
1.1.1.9 root 14869: case 0x61:
14870: if((system_port & 3) != 3 && (val & 3) == 3) {
14871: // beep on
14872: // MessageBeep(-1);
14873: } else if((system_port & 3) == 3 && (val & 3) != 3) {
14874: // beep off
14875: }
14876: system_port = val;
14877: break;
1.1 root 14878: case 0x64:
1.1.1.7 root 14879: kbd_write_command(val);
1.1 root 14880: break;
14881: case 0x70:
14882: cmos_addr = val;
14883: break;
14884: case 0x71:
1.1.1.8 root 14885: cmos_write(cmos_addr, val);
1.1 root 14886: break;
1.1.1.25 root 14887: case 0x81:
14888: dma_page_write(0, 2, val);
14889: case 0x82:
14890: dma_page_write(0, 3, val);
14891: case 0x83:
14892: dma_page_write(0, 1, val);
14893: case 0x87:
14894: dma_page_write(0, 0, val);
14895: case 0x89:
14896: dma_page_write(1, 2, val);
14897: case 0x8a:
14898: dma_page_write(1, 3, val);
14899: case 0x8b:
14900: dma_page_write(1, 1, val);
14901: case 0x8f:
14902: dma_page_write(1, 0, val);
1.1 root 14903: case 0x92:
1.1.1.7 root 14904: i386_set_a20_line((val >> 1) & 1);
1.1 root 14905: break;
1.1.1.25 root 14906: case 0xa0: case 0xa1:
1.1 root 14907: pic_write(1, addr, val);
14908: break;
1.1.1.25 root 14909: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
14910: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 14911: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 14912: break;
1.1.1.26 root 14913: // case 0x278: case 0x279: case 0x27a:
14914: // pio_write(1, addr, val);
14915: // break;
1.1.1.29 root 14916: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
14917: sio_write(3, addr, val);
14918: break;
1.1.1.25 root 14919: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
14920: sio_write(1, addr, val);
14921: break;
14922: case 0x378: case 0x379: case 0x37a:
14923: pio_write(0, addr, val);
14924: break;
1.1.1.29 root 14925: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
14926: sio_write(2, addr, val);
14927: break;
1.1.1.25 root 14928: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
14929: sio_write(0, addr, val);
14930: break;
1.1 root 14931: default:
14932: // error("outb %4x,%2x\n", addr, val);
14933: break;
14934: }
14935: }
14936:
14937: void write_io_word(offs_t addr, UINT16 val)
14938: {
14939: write_io_byte(addr + 0, (val >> 0) & 0xff);
14940: write_io_byte(addr + 1, (val >> 8) & 0xff);
14941: }
14942:
14943: void write_io_dword(offs_t addr, UINT32 val)
14944: {
14945: write_io_byte(addr + 0, (val >> 0) & 0xff);
14946: write_io_byte(addr + 1, (val >> 8) & 0xff);
14947: write_io_byte(addr + 2, (val >> 16) & 0xff);
14948: write_io_byte(addr + 3, (val >> 24) & 0xff);
14949: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.