|
|
1.1.1.67 root 1: /*
2: MS-DOS Player for Win32 console
3:
4: Author : Takeda.Toshiya
5: Date : 2009.11.09-
6: */
7:
8: #include "msdos.h"
9:
10: void exit_handler();
11:
12: #define fatalerror(...) { \
13: fprintf(stderr, __VA_ARGS__); \
14: exit_handler(); \
15: exit(1); \
16: }
17: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
18: #define nolog(...)
19:
20: //#define ENABLE_DEBUG_LOG
21: #ifdef ENABLE_DEBUG_LOG
22: #define EXPORT_DEBUG_TO_FILE
23: #define ENABLE_DEBUG_SYSCALL
24: #define ENABLE_DEBUG_UNIMPLEMENTED
25: #define ENABLE_DEBUG_IOPORT
26:
27: #ifdef EXPORT_DEBUG_TO_FILE
28: FILE* fp_debug_log = NULL;
29: #else
30: #define fp_debug_log stderr
31: #endif
32: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
33: #define unimplemented_10h fatalerror
34: #define unimplemented_13h fatalerror
35: #define unimplemented_14h fatalerror
36: #define unimplemented_15h fatalerror
37: #define unimplemented_16h fatalerror
38: #define unimplemented_17h fatalerror
39: #define unimplemented_1ah fatalerror
40: #define unimplemented_21h fatalerror
41: #define unimplemented_2fh fatalerror
42: #define unimplemented_33h fatalerror
43: #define unimplemented_67h fatalerror
44: #define unimplemented_xms fatalerror
45: #endif
46: #endif
47: #ifndef unimplemented_10h
48: #define unimplemented_10h nolog
49: #endif
50: #ifndef unimplemented_13h
51: #define unimplemented_13h nolog
52: #endif
53: #ifndef unimplemented_14h
54: #define unimplemented_14h nolog
55: #endif
56: #ifndef unimplemented_15h
57: #define unimplemented_15h nolog
58: #endif
59: #ifndef unimplemented_16h
60: #define unimplemented_16h nolog
61: #endif
62: #ifndef unimplemented_17h
63: #define unimplemented_17h nolog
64: #endif
65: #ifndef unimplemented_1ah
66: #define unimplemented_1ah nolog
67: #endif
68: #ifndef unimplemented_21h
69: #define unimplemented_21h nolog
70: #endif
71: #ifndef unimplemented_2fh
72: #define unimplemented_2fh nolog
73: #endif
74: #ifndef unimplemented_33h
75: #define unimplemented_33h nolog
76: #endif
77: #ifndef unimplemented_67h
78: #define unimplemented_67h nolog
79: #endif
80: #ifndef unimplemented_xms
81: #define unimplemented_xms nolog
82: #endif
83:
84: #ifdef _MBCS
85: inline char *my_strchr(char *str, int chr)
86: {
87: return (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr));
88: }
89: inline const char *my_strchr(const char *str, int chr)
90: {
91: return (const char *)_mbschr((const unsigned char *)(str), (unsigned int)(chr));
92: }
93: inline char *my_strrchr(char *str, int chr)
94: {
95: return (char *)_mbsrchr((unsigned char *)(str), (unsigned int)(chr));
96: }
97: inline const char *my_strrchr(const char *str, int chr)
98: {
99: return (const char *)_mbsrchr((const unsigned char *)(str), (unsigned int)(chr));
100: }
101: inline char *my_strtok(char *tok, const char *del)
102: {
103: return (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del));
104: }
105: inline char *my_strupr(char *str)
106: {
107: return (char *)_mbsupr((unsigned char *)(str));
108: }
109: #else
110: #define my_strchr(str, chr) strchr((str), (chr))
111: #define my_strrchr(str, chr) strrchr((str), (chr))
112: #define my_strtok(tok, del) strtok((tok), (del))
113: #define my_strupr(str) _strupr((str))
114: #endif
115: #define array_length(array) (sizeof(array) / sizeof(array[0]))
116:
117: #if defined(__MINGW32__)
118: extern "C" int _CRT_glob = 0;
119: #endif
120:
121: /*
122: kludge for "more-standardized" C++
123: */
124: #if !defined(_MSC_VER)
125: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
126: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
127: #define min(a,b) kludge_min(a,b)
128: #define max(a,b) kludge_max(a,b)
129: #elif _MSC_VER >= 1400
130: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
131: {
132: }
133: #endif
134:
135: #define USE_VRAM_THREAD
136:
137: #ifdef USE_VRAM_THREAD
138: static CRITICAL_SECTION vram_crit_sect;
139: #else
140: #define vram_flush()
141: #endif
142:
143: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
144: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
145:
146: void change_console_size(int width, int height);
147: void clear_scr_buffer(WORD attr);
148:
149: static UINT32 vram_length_char = 0, vram_length_attr = 0;
150: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
151: static COORD vram_coord_char, vram_coord_attr;
152:
153: char temp_file_path[MAX_PATH];
154: bool temp_file_created = false;
155:
156: bool ignore_illegal_insn = false;
157: bool limit_max_memory = false;
158: bool no_windows = false;
159: bool stay_busy = false;
160: bool support_ems = false;
161: #ifdef SUPPORT_XMS
162: bool support_xms = false;
163: #endif
164: int sio_port_number[4] = {0, 0, 0, 0};
165:
166: BOOL is_winxp_or_later;
167: BOOL is_xp_64_or_later;
168: BOOL is_vista_or_later;
169:
170: #define UPDATE_OPS 16384
171: #define REQUEST_HARDWRE_UPDATE() { \
172: update_ops = UPDATE_OPS - 1; \
173: }
174: UINT32 update_ops = 0;
175: UINT32 idle_ops = 0;
176:
177: inline BOOL is_sse2_ready()
178: {
179: static int result = -1;
180: int cpu_info[4];
181:
182: if(result == -1) {
183: result = 0;
184: __cpuid(cpu_info, 0);
185: if(cpu_info[0] >= 1){
186: __cpuid(cpu_info, 1);
187: if(cpu_info[3] & (1 << 26)) {
188: result = 1;
189: }
190: }
191: }
192: return(result == 1);
193: }
194:
195: inline void maybe_idle()
196: {
197: // if it appears to be in a tight loop, assume waiting for input
198: // allow for one updated video character, for a spinning cursor
199: if(!stay_busy && idle_ops < 1024 && vram_length_char <= 1 && vram_length_attr <= 1) {
200: if(is_sse2_ready()) {
201: _mm_pause(); // SSE2 pause
202: } else if(is_xp_64_or_later) {
203: Sleep(0); // switch to other thread that is ready to run, without checking priority
204: } else {
205: Sleep(1);
206: REQUEST_HARDWRE_UPDATE();
207: }
208: }
209: idle_ops = 0;
210: }
211:
212: /* ----------------------------------------------------------------------------
213: MAME i86/i386
214: ---------------------------------------------------------------------------- */
215:
216: #ifndef __BIG_ENDIAN__
217: #define LSB_FIRST
218: #endif
219:
220: #ifndef INLINE
221: #define INLINE inline
222: #endif
223: #define U64(v) UINT64(v)
224:
225: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
226: #define logerror(...)
227: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
228: #define popmessage(...)
229:
230: /*****************************************************************************/
231: /* src/emu/devcpu.h */
232:
233: // CPU interface functions
234: #define CPU_INIT_NAME(name) cpu_init_##name
235: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
236: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
237:
238: #define CPU_RESET_NAME(name) cpu_reset_##name
239: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
240: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
241:
242: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
243: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
244: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
245:
246: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
247: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
248: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
249:
250: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
251: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
252: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
253:
254: #define CPU_MODEL_STR(name) #name
255: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
256:
257: /*****************************************************************************/
258: /* src/emu/didisasm.h */
259:
260: // Disassembler constants
261: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
262: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
263: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
264: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
265: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
266: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
267:
268: /*****************************************************************************/
269: /* src/emu/diexec.h */
270:
271: // I/O line states
272: enum line_state
273: {
274: CLEAR_LINE = 0, // clear (a fired or held) line
275: ASSERT_LINE, // assert an interrupt immediately
276: HOLD_LINE, // hold interrupt line until acknowledged
277: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
278: };
279:
280: // I/O line definitions
281: enum
282: {
283: INPUT_LINE_IRQ = 0,
284: INPUT_LINE_NMI
285: };
286:
287: /*****************************************************************************/
288: /* src/emu/dimemory.h */
289:
290: // Translation intentions
291: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
292: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
293: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
294:
295: const int TRANSLATE_READ = 0; // translate for read
296: const int TRANSLATE_WRITE = 1; // translate for write
297: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
298: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
299: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
300: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
301: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
302: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
303: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
304:
305: /*****************************************************************************/
306: /* src/emu/emucore.h */
307:
308: // constants for expression endianness
309: enum endianness_t
310: {
311: ENDIANNESS_LITTLE,
312: ENDIANNESS_BIG
313: };
314:
315: // declare native endianness to be one or the other
316: #ifdef LSB_FIRST
317: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
318: #else
319: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
320: #endif
321:
322: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
323: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
324:
325: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
326: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
327:
328: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
329: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
330:
331: /*****************************************************************************/
332: /* src/emu/emumem.h */
333:
334: // helpers for checking address alignment
335: #define WORD_ALIGNED(a) (((a) & 1) == 0)
336: #define DWORD_ALIGNED(a) (((a) & 3) == 0)
337: #define QWORD_ALIGNED(a) (((a) & 7) == 0)
338:
339: /*****************************************************************************/
340: /* src/emu/memory.h */
341:
342: // address spaces
343: enum address_spacenum
344: {
345: AS_0, // first address space
346: AS_1, // second address space
347: AS_2, // third address space
348: AS_3, // fourth address space
349: ADDRESS_SPACES, // maximum number of address spaces
350:
351: // alternate address space names for common use
352: AS_PROGRAM = AS_0, // program address space
353: AS_DATA = AS_1, // data address space
354: AS_IO = AS_2 // I/O address space
355: };
356:
357: // offsets and addresses are 32-bit (for now...)
358: //typedef UINT32 offs_t;
359:
360: // read accessors
361: UINT8 read_byte(offs_t byteaddress)
362: #ifdef USE_DEBUGGER
363: {
364: if(now_debugging) {
365: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
366: if(rd_break_point.table[i].status == 1) {
367: if(byteaddress == rd_break_point.table[i].addr) {
368: rd_break_point.hit = i + 1;
369: now_suspended = true;
370: break;
371: }
372: }
373: }
374: }
375: return(debugger_read_byte(byteaddress));
376: }
377: UINT8 debugger_read_byte(offs_t byteaddress)
378: #endif
379: {
380: #if defined(HAS_I386)
381: if(byteaddress < MAX_MEM) {
382: return mem[byteaddress];
383: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
384: // return read_byte(byteaddress & 0xfffff);
385: }
386: return 0;
387: #else
388: return mem[byteaddress];
389: #endif
390: }
391:
392: UINT16 read_word(offs_t byteaddress)
393: #ifdef USE_DEBUGGER
394: {
395: if(now_debugging) {
396: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
397: if(rd_break_point.table[i].status == 1) {
398: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 2) {
399: rd_break_point.hit = i + 1;
400: now_suspended = true;
401: break;
402: }
403: }
404: }
405: }
406: return(debugger_read_word(byteaddress));
407: }
408: UINT16 debugger_read_word(offs_t byteaddress)
409: #endif
410: {
411: if(byteaddress == 0x41c) {
412: // pointer to first free slot in keyboard buffer
413: if(key_buf_char != NULL && key_buf_scan != NULL) {
414: #ifdef USE_SERVICE_THREAD
415: EnterCriticalSection(&key_buf_crit_sect);
416: #endif
417: bool empty = pcbios_is_key_buffer_empty();
418: #ifdef USE_SERVICE_THREAD
419: LeaveCriticalSection(&key_buf_crit_sect);
420: #endif
421: if(empty) maybe_idle();
422: }
423: }
424: #if defined(HAS_I386)
425: if(byteaddress < MAX_MEM - 1) {
426: return *(UINT16 *)(mem + byteaddress);
427: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
428: // return read_word(byteaddress & 0xfffff);
429: }
430: return 0;
431: #else
432: return *(UINT16 *)(mem + byteaddress);
433: #endif
434: }
435:
436: UINT32 read_dword(offs_t byteaddress)
437: #ifdef USE_DEBUGGER
438: {
439: if(now_debugging) {
440: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
441: if(rd_break_point.table[i].status == 1) {
442: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 4) {
443: rd_break_point.hit = i + 1;
444: now_suspended = true;
445: break;
446: }
447: }
448: }
449: }
450: return(debugger_read_dword(byteaddress));
451: }
452: UINT32 debugger_read_dword(offs_t byteaddress)
453: #endif
454: {
455: #if defined(HAS_I386)
456: if(byteaddress < MAX_MEM - 3) {
457: return *(UINT32 *)(mem + byteaddress);
458: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
459: // return read_dword(byteaddress & 0xfffff);
460: }
461: return 0;
462: #else
463: return *(UINT32 *)(mem + byteaddress);
464: #endif
465: }
466:
467: // write accessors
468: #ifdef USE_VRAM_THREAD
469: void vram_flush_char()
470: {
471: if(vram_length_char != 0) {
472: DWORD num;
473: WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
474: vram_length_char = vram_last_length_char = 0;
475: }
476: }
477:
478: void vram_flush_attr()
479: {
480: if(vram_length_attr != 0) {
481: DWORD num;
482: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
483: vram_length_attr = vram_last_length_attr = 0;
484: }
485: }
486:
487: void vram_flush()
488: {
489: if(vram_length_char != 0 || vram_length_attr != 0) {
490: EnterCriticalSection(&vram_crit_sect);
491: vram_flush_char();
492: vram_flush_attr();
493: LeaveCriticalSection(&vram_crit_sect);
494: }
495: }
496: #endif
497:
498: void write_text_vram_char(offs_t offset, UINT8 data)
499: {
500: #ifdef USE_VRAM_THREAD
501: static offs_t first_offset_char, last_offset_char;
502:
503: if(vram_length_char != 0) {
504: if(offset <= last_offset_char && offset >= first_offset_char) {
505: scr_char[(offset - first_offset_char) >> 1] = data;
506: return;
507: }
508: if(offset != last_offset_char + 2) {
509: vram_flush_char();
510: }
511: }
512: if(vram_length_char == 0) {
513: first_offset_char = offset;
514: vram_coord_char.X = (offset >> 1) % scr_width;
515: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
516: }
517: scr_char[vram_length_char++] = data;
518: last_offset_char = offset;
519: #else
520: COORD co;
521: DWORD num;
522:
523: co.X = (offset >> 1) % scr_width;
524: co.Y = (offset >> 1) / scr_width;
525: scr_char[0] = data;
526: WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
527: #endif
528: }
529:
530: void write_text_vram_attr(offs_t offset, UINT8 data)
531: {
532: #ifdef USE_VRAM_THREAD
533: static offs_t first_offset_attr, last_offset_attr;
534:
535: if(vram_length_attr != 0) {
536: if(offset <= last_offset_attr && offset >= first_offset_attr) {
537: scr_attr[(offset - first_offset_attr) >> 1] = data;
538: return;
539: }
540: if(offset != last_offset_attr + 2) {
541: vram_flush_attr();
542: }
543: }
544: if(vram_length_attr == 0) {
545: first_offset_attr = offset;
546: vram_coord_attr.X = (offset >> 1) % scr_width;
547: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
548: }
549: scr_attr[vram_length_attr++] = data;
550: last_offset_attr = offset;
551: #else
552: COORD co;
553: DWORD num;
554:
555: co.X = (offset >> 1) % scr_width;
556: co.Y = (offset >> 1) / scr_width;
557: scr_attr[0] = data;
558: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
559: #endif
560: }
561:
562: void write_text_vram_byte(offs_t offset, UINT8 data)
563: {
564: #ifdef USE_VRAM_THREAD
565: EnterCriticalSection(&vram_crit_sect);
566: #endif
567: if(offset & 1) {
568: write_text_vram_attr(offset, data);
569: } else {
570: write_text_vram_char(offset, data);
571: }
572: #ifdef USE_VRAM_THREAD
573: LeaveCriticalSection(&vram_crit_sect);
574: #endif
575: }
576:
577: void write_text_vram_word(offs_t offset, UINT16 data)
578: {
579: #ifdef USE_VRAM_THREAD
580: EnterCriticalSection(&vram_crit_sect);
581: #endif
582: if(offset & 1) {
583: write_text_vram_attr(offset , (data ) & 0xff);
584: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
585: } else {
586: write_text_vram_char(offset , (data ) & 0xff);
587: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
588: }
589: #ifdef USE_VRAM_THREAD
590: LeaveCriticalSection(&vram_crit_sect);
591: #endif
592: }
593:
594: void write_text_vram_dword(offs_t offset, UINT32 data)
595: {
596: #ifdef USE_VRAM_THREAD
597: EnterCriticalSection(&vram_crit_sect);
598: #endif
599: if(offset & 1) {
600: write_text_vram_attr(offset , (data ) & 0xff);
601: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
602: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
603: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
604: } else {
605: write_text_vram_char(offset , (data ) & 0xff);
606: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
607: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
608: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
609: }
610: #ifdef USE_VRAM_THREAD
611: LeaveCriticalSection(&vram_crit_sect);
612: #endif
613: }
614:
615: void write_byte(offs_t byteaddress, UINT8 data)
616: #ifdef USE_DEBUGGER
617: {
618: if(now_debugging) {
619: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
620: if(wr_break_point.table[i].status == 1) {
621: if(byteaddress == wr_break_point.table[i].addr) {
622: wr_break_point.hit = i + 1;
623: now_suspended = true;
624: break;
625: }
626: }
627: }
628: }
629: debugger_write_byte(byteaddress, data);
630: }
631: void debugger_write_byte(offs_t byteaddress, UINT8 data)
632: #endif
633: {
634: if(byteaddress < MEMORY_END) {
635: mem[byteaddress] = data;
636: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
637: if(!restore_console_on_exit) {
638: change_console_size(scr_width, scr_height);
639: }
640: write_text_vram_byte(byteaddress - text_vram_top_address, data);
641: mem[byteaddress] = data;
642: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
643: if(int_10h_feh_called && !int_10h_ffh_called) {
644: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
645: }
646: mem[byteaddress] = data;
647: #if defined(HAS_I386)
648: } else if(byteaddress < MAX_MEM) {
649: #else
650: } else {
651: #endif
652: mem[byteaddress] = data;
653: }
654: }
655:
656: void write_word(offs_t byteaddress, UINT16 data)
657: #ifdef USE_DEBUGGER
658: {
659: if(now_debugging) {
660: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
661: if(wr_break_point.table[i].status == 1) {
662: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 2) {
663: wr_break_point.hit = i + 1;
664: now_suspended = true;
665: break;
666: }
667: }
668: }
669: }
670: debugger_write_word(byteaddress, data);
671: }
672: void debugger_write_word(offs_t byteaddress, UINT16 data)
673: #endif
674: {
675: if(byteaddress < MEMORY_END) {
676: if(byteaddress == cursor_position_address) {
677: if(*(UINT16 *)(mem + byteaddress) != data) {
678: COORD co;
679: co.X = data & 0xff;
680: co.Y = (data >> 8) + scr_top;
681: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
682: cursor_moved = false;
683: cursor_moved_by_crtc = false;
684: }
685: }
686: *(UINT16 *)(mem + byteaddress) = data;
687: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
688: if(!restore_console_on_exit) {
689: change_console_size(scr_width, scr_height);
690: }
691: write_text_vram_word(byteaddress - text_vram_top_address, data);
692: *(UINT16 *)(mem + byteaddress) = data;
693: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
694: if(int_10h_feh_called && !int_10h_ffh_called) {
695: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
696: }
697: *(UINT16 *)(mem + byteaddress) = data;
698: #if defined(HAS_I386)
699: } else if(byteaddress < MAX_MEM - 1) {
700: #else
701: } else {
702: #endif
703: *(UINT16 *)(mem + byteaddress) = data;
704: }
705: }
706:
707: void write_dword(offs_t byteaddress, UINT32 data)
708: #ifdef USE_DEBUGGER
709: {
710: if(now_debugging) {
711: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
712: if(wr_break_point.table[i].status == 1) {
713: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 4) {
714: wr_break_point.hit = i + 1;
715: now_suspended = true;
716: break;
717: }
718: }
719: }
720: }
721: debugger_write_dword(byteaddress, data);
722: }
723: void debugger_write_dword(offs_t byteaddress, UINT32 data)
724: #endif
725: {
726: if(byteaddress < MEMORY_END) {
727: *(UINT32 *)(mem + byteaddress) = data;
728: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
729: if(!restore_console_on_exit) {
730: change_console_size(scr_width, scr_height);
731: }
732: write_text_vram_dword(byteaddress - text_vram_top_address, data);
733: *(UINT32 *)(mem + byteaddress) = data;
734: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
735: if(int_10h_feh_called && !int_10h_ffh_called) {
736: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
737: }
738: *(UINT32 *)(mem + byteaddress) = data;
739: #if defined(HAS_I386)
740: } else if(byteaddress < MAX_MEM - 3) {
741: #else
742: } else {
743: #endif
744: *(UINT32 *)(mem + byteaddress) = data;
745: }
746: }
747:
748: #define read_decrypted_byte read_byte
749: #define read_decrypted_word read_word
750: #define read_decrypted_dword read_dword
751:
752: #define read_raw_byte read_byte
753: #define write_raw_byte write_byte
754:
755: #define read_word_unaligned read_word
756: #define write_word_unaligned write_word
757:
758: #define read_io_word_unaligned read_io_word
759: #define write_io_word_unaligned write_io_word
760:
761: UINT8 read_io_byte(offs_t byteaddress);
762: UINT16 read_io_word(offs_t byteaddress);
763: UINT32 read_io_dword(offs_t byteaddress);
764:
765: void write_io_byte(offs_t byteaddress, UINT8 data);
766: void write_io_word(offs_t byteaddress, UINT16 data);
767: void write_io_dword(offs_t byteaddress, UINT32 data);
768:
769: /*****************************************************************************/
770: /* src/osd/osdcomm.h */
771:
772: /* Highly useful macro for compile-time knowledge of an array size */
773: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
774:
775: // flag to exit MS-DOS Player
776: // this is set when the first process is terminated and jump to FFFF:0000 HALT
777: int m_exit = 0;
778:
779: #if defined(HAS_I386)
780: static CPU_TRANSLATE(i386);
781: #include "mame/lib/softfloat/softfloat.c"
782: #include "mame/lib/softfloat/fsincos.c"
783: #include "mame/emu/cpu/i386/i386.c"
784: #include "mame/emu/cpu/vtlb.c"
785: #elif defined(HAS_I286)
786: #include "mame/emu/cpu/i86/i286.c"
787: #else
788: #include "mame/emu/cpu/i86/i86.c"
789: #endif
790: #ifdef USE_DEBUGGER
791: #include "mame/emu/cpu/i386/i386dasm.c"
792: #endif
793:
794: #if defined(HAS_I386)
795: #define SREG(x) m_sreg[x].selector
796: #define SREG_BASE(x) m_sreg[x].base
797: int cpu_type, cpu_step;
798: #define i386_get_flags() get_flags()
799: #define i386_set_flags(x) set_flags(x)
800: #else
801: #define REG8(x) m_regs.b[x]
802: #define REG16(x) m_regs.w[x]
803: #define SREG(x) m_sregs[x]
804: #define SREG_BASE(x) m_base[x]
805: #define m_eip (m_pc - m_base[CS])
806: #define m_CF m_CarryVal
807: #define m_a20_mask AMASK
808: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
809: void i386_sreg_load(UINT16 selector, UINT8 reg, bool *fault)
810: {
811: #if defined(HAS_I286)
812: i80286_data_descriptor(reg, selector);
813: #else
814: m_sregs[reg] = selector;
815: m_base[reg] = SegBase(reg);
816: #endif
817: }
818: #define i386_get_flags() CompressFlags()
819: #define i386_set_flags(x) ExpandFlags(x)
820: #if defined(HAS_I286)
821: #define i386_set_a20_line(x) i80286_set_a20_line(x)
822: #else
823: #define i386_set_a20_line(x)
824: #endif
825: #define i386_set_irq_line(x, y) set_irq_line(x, y)
826: #endif
827:
828: void i386_jmp_far(UINT16 selector, UINT32 address)
829: {
830: #if defined(HAS_I386)
831: if(PROTECTED_MODE && !V8086_MODE) {
832: i386_protected_mode_jump(selector, address, 1, m_operand_size);
833: } else {
834: SREG(CS) = selector;
835: m_performed_intersegment_jump = 1;
836: i386_load_segment_descriptor(CS);
837: m_eip = address;
838: CHANGE_PC(m_eip);
839: }
840: #elif defined(HAS_I286)
841: i80286_code_descriptor(selector, address, 1);
842: #else
843: SREG(CS) = selector;
844: i386_load_segment_descriptor(CS);
845: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
846: #endif
847: }
848:
849: void i386_call_far(UINT16 selector, UINT32 address)
850: {
851: #if defined(HAS_I386)
852: if(PROTECTED_MODE && !V8086_MODE) {
853: i386_protected_mode_call(selector, address, 1, m_operand_size);
854: } else {
855: PUSH16(SREG(CS));
856: PUSH16(m_eip);
857: SREG(CS) = selector;
858: m_performed_intersegment_jump = 1;
859: i386_load_segment_descriptor(CS);
860: m_eip = address;
861: CHANGE_PC(m_eip);
862: }
863: #else
864: UINT16 ip = m_pc - SREG_BASE(CS);
865: UINT16 cs = SREG(CS);
866: #if defined(HAS_I286)
867: i80286_code_descriptor(selector, address, 2);
868: #else
869: SREG(CS) = selector;
870: i386_load_segment_descriptor(CS);
871: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
872: #endif
873: PUSH(cs);
874: PUSH(ip);
875: CHANGE_PC(m_pc);
876: #endif
877: }
878:
879: void i386_push16(UINT16 value)
880: {
881: #if defined(HAS_I386)
882: PUSH16(value);
883: #else
884: PUSH(value);
885: #endif
886: }
887:
888: UINT16 i386_pop16()
889: {
890: #if defined(HAS_I386)
891: return POP16();
892: #else
893: UINT16 value;
894: POP(value);
895: return value;
896: #endif
897: }
898:
899: UINT16 i386_read_stack()
900: {
901: #if defined(HAS_I386)
902: UINT32 ea, new_esp;
903: if( STACK_32BIT ) {
904: new_esp = REG32(ESP) + 2;
905: ea = i386_translate(SS, new_esp - 2, 0, 2);
906: } else {
907: new_esp = REG16(SP) + 2;
908: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0, 2);
909: }
910: return READ16(ea);
911: #else
912: UINT16 sp = m_regs.w[SP] + 2;
913: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
914: #endif
915: }
916:
917: void i386_write_stack(UINT16 value)
918: {
919: #if defined(HAS_I386)
920: UINT32 ea, new_esp;
921: if( STACK_32BIT ) {
922: new_esp = REG32(ESP) + 2;
923: ea = i386_translate(SS, new_esp - 2, 0, 2);
924: } else {
925: new_esp = REG16(SP) + 2;
926: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0, 2);
927: }
928: WRITE16(ea, value);
929: #else
930: UINT16 sp = m_regs.w[SP] + 2;
931: WriteWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK), value);
932: #endif
933: }
934:
935: /* ----------------------------------------------------------------------------
936: debugger
937: ---------------------------------------------------------------------------- */
938:
939: #ifdef USE_DEBUGGER
940: #define TELNET_BLUE 0x0004 // text color contains blue.
941: #define TELNET_GREEN 0x0002 // text color contains green.
942: #define TELNET_RED 0x0001 // text color contains red.
943: #define TELNET_INTENSITY 0x0008 // text color is intensified.
944:
945: int svr_socket = 0;
946: int cli_socket = 0;
947:
948: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error);
949:
950: void debugger_init()
951: {
952: now_debugging = false;
953: now_going = false;
954: now_suspended = false;
955: force_suspend = false;
956:
957: memset(&break_point, 0, sizeof(break_point_t));
958: memset(&rd_break_point, 0, sizeof(break_point_t));
959: memset(&wr_break_point, 0, sizeof(break_point_t));
960: memset(&in_break_point, 0, sizeof(break_point_t));
961: memset(&out_break_point, 0, sizeof(break_point_t));
962: memset(&int_break_point, 0, sizeof(int_break_point_t));
963: }
964:
965: void telnet_send(const char *string)
966: {
967: char buffer[8192], *ptr;
968: strcpy(buffer, string);
969: while((ptr = strstr(buffer, "\n")) != NULL) {
970: char tmp[8192];
971: *ptr = '\0';
972: sprintf(tmp, "%s\033E%s", buffer, ptr + 1);
973: strcpy(buffer, tmp);
974: }
975:
976: int len = strlen(buffer), res;
977: ptr = buffer;
978: while(len > 0) {
979: if((res = send(cli_socket, ptr, len, 0)) > 0) {
980: len -= res;
981: ptr += res;
982: }
983: }
984: }
985:
986: void telnet_command(const char *format, ...)
987: {
988: char buffer[1024];
989: va_list ap;
990: va_start(ap, format);
991: vsprintf(buffer, format, ap);
992: va_end(ap);
993:
994: telnet_send(buffer);
995: }
996:
997: void telnet_printf(const char *format, ...)
998: {
999: char buffer[1024];
1000: va_list ap;
1001: va_start(ap, format);
1002: vsprintf(buffer, format, ap);
1003: va_end(ap);
1004:
1005: if(fp_debugger != NULL) {
1006: fprintf(fp_debugger, "%s", buffer);
1007: }
1008: telnet_send(buffer);
1009: }
1010:
1011: bool telnet_gets(char *str, int n)
1012: {
1013: char buffer[1024];
1014: int ptr = 0;
1015:
1016: telnet_command("\033[12l"); // local echo on
1017: telnet_command("\033[2l"); // key unlock
1018:
1019: while(!m_exit) {
1020: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
1021:
1022: if(len > 0 && buffer[0] != 0xff) {
1023: for(int i = 0; i < len; i++) {
1024: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
1025: str[ptr] = 0;
1026: telnet_command("\033[2h"); // key lock
1027: telnet_command("\033[12h"); // local echo off
1028: return(!m_exit);
1029: } else if(buffer[i] == 0x08) {
1030: if(ptr > 0) {
1031: telnet_command("\033[0K"); // erase from cursor position
1032: ptr--;
1033: } else {
1034: telnet_command("\033[1C"); // move cursor forward
1035: }
1036: } else if(ptr < n - 1) {
1037: if(buffer[i] >= 0x20 && buffer[i] <= 0x7e) {
1038: str[ptr++] = buffer[i];
1039: }
1040: } else {
1041: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position
1042: }
1043: }
1044: } else if(len == -1) {
1045: if(WSAGetLastError() != WSAEWOULDBLOCK) {
1046: return(false);
1047: }
1048: } else if(len == 0) {
1049: return(false);
1050: }
1051: Sleep(10);
1052: }
1053: return(!m_exit);
1054: }
1055:
1056: bool telnet_kbhit()
1057: {
1058: char buffer[1024];
1059:
1060: if(!m_exit) {
1061: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
1062:
1063: if(len > 0) {
1064: for(int i = 0; i < len; i++) {
1065: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
1066: return(true);
1067: }
1068: }
1069: } else if(len == 0) {
1070: return(true); // disconnected
1071: }
1072: }
1073: return(false);
1074: }
1075:
1076: bool telnet_disconnected()
1077: {
1078: char buffer[1024];
1079: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
1080:
1081: if(len == 0) {
1082: return(true);
1083: } else if(len == -1) {
1084: if(WSAGetLastError() != WSAEWOULDBLOCK) {
1085: return(true);
1086: }
1087: }
1088: return(false);
1089: }
1090:
1091: void telnet_set_color(int color)
1092: {
1093: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7));
1094: }
1095:
1096: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip)
1097: {
1098: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1));
1099: UINT8 ops[16];
1100: for(int i = 0; i < 16; i++) {
1101: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK);
1102: }
1103: UINT8 *oprom = ops;
1104:
1105: #if defined(HAS_I386)
1106: if(m_operand_size) {
1107: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK);
1108: } else
1109: #endif
1110: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK);
1111: }
1112:
1113: void debugger_regs_info(char *buffer)
1114: {
1115: UINT32 flags = i386_get_flags();
1116:
1117: #if defined(HAS_I386)
1118: if(m_operand_size) {
1119: sprintf(buffer, "EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nESP=%08X EBP=%08X ESI=%08X EDI=%08X\nEIP=%08X DS=%04X ES=%04X SS=%04X CS=%04X FLAG=[%c %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
1120: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), m_eip, SREG(DS), SREG(ES), SREG(SS), SREG(CS),
1121: PROTECTED_MODE ? "PE" : "--",
1122: (flags & 0x40000) ? 'A' : '-',
1123: (flags & 0x20000) ? 'V' : '-',
1124: (flags & 0x10000) ? 'R' : '-',
1125: (flags & 0x04000) ? 'N' : '-',
1126: (flags & 0x02000) ? '1' : '0',
1127: (flags & 0x01000) ? '1' : '0',
1128: (flags & 0x00800) ? 'O' : '-',
1129: (flags & 0x00400) ? 'D' : '-',
1130: (flags & 0x00200) ? 'I' : '-',
1131: (flags & 0x00100) ? 'T' : '-',
1132: (flags & 0x00080) ? 'S' : '-',
1133: (flags & 0x00040) ? 'Z' : '-',
1134: (flags & 0x00010) ? 'A' : '-',
1135: (flags & 0x00004) ? 'P' : '-',
1136: (flags & 0x00001) ? 'C' : '-');
1137: } else {
1138: #endif
1139: sprintf(buffer, "AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X\nIP=%04X DS=%04X ES=%04X SS=%04X CS=%04X FLAG=[%c %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
1140: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), m_eip, SREG(DS), SREG(ES), SREG(SS), SREG(CS),
1141: #if defined(HAS_I386)
1142: PROTECTED_MODE ? "PE" : "--",
1143: #else
1144: "--",
1145: #endif
1146: (flags & 0x40000) ? 'A' : '-',
1147: (flags & 0x20000) ? 'V' : '-',
1148: (flags & 0x10000) ? 'R' : '-',
1149: (flags & 0x04000) ? 'N' : '-',
1150: (flags & 0x02000) ? '1' : '0',
1151: (flags & 0x01000) ? '1' : '0',
1152: (flags & 0x00800) ? 'O' : '-',
1153: (flags & 0x00400) ? 'D' : '-',
1154: (flags & 0x00200) ? 'I' : '-',
1155: (flags & 0x00100) ? 'T' : '-',
1156: (flags & 0x00080) ? 'S' : '-',
1157: (flags & 0x00040) ? 'Z' : '-',
1158: (flags & 0x00010) ? 'A' : '-',
1159: (flags & 0x00004) ? 'P' : '-',
1160: (flags & 0x00001) ? 'C' : '-');
1161: #if defined(HAS_I386)
1162: }
1163: #endif
1164: }
1165:
1166: void debugger_process_info(char *buffer)
1167: {
1168: UINT16 psp_seg = current_psp;
1169: process_t *process;
1170: bool check[0x10000] = {0};
1171:
1172: buffer[0] = '\0';
1173:
1174: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) {
1175: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1176: char *file = process->module_path, *s;
1177: char tmp[8192];
1178:
1179: while((s = strstr(file, "\\")) != NULL) {
1180: file = s + 1;
1181: }
1182: sprintf(tmp, "PSP=%04X ENV=%04X RETURN=%04X:%04X PROGRAM=%s\n", psp_seg, psp->env_seg, psp->int_22h.w.h, psp->int_22h.w.l, my_strupr(file));
1183: strcat(tmp, buffer);
1184: strcpy(buffer, tmp);
1185:
1186: check[psp_seg] = true;
1187: psp_seg = psp->parent_psp;
1188: }
1189: }
1190:
1191: UINT32 debugger_get_val(const char *str)
1192: {
1193: char tmp[1024];
1194:
1195: if(str == NULL || strlen(str) == 0) {
1196: return(0);
1197: }
1198: strcpy(tmp, str);
1199:
1200: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') {
1201: // ank
1202: return(tmp[1] & 0xff);
1203: } else if(tmp[0] == '%') {
1204: // decimal
1205: return(strtoul(tmp + 1, NULL, 10));
1206: }
1207: return(strtoul(tmp, NULL, 16));
1208: }
1209:
1210: UINT32 debugger_get_seg(const char *str, UINT32 val)
1211: {
1212: char tmp[1024], *s;
1213:
1214: if(str == NULL || strlen(str) == 0) {
1215: return(val);
1216: }
1217: strcpy(tmp, str);
1218:
1219: if((s = strstr(tmp, ":")) != NULL) {
1220: // 0000:0000
1221: *s = '\0';
1222: return(debugger_get_val(tmp));
1223: }
1224: return(val);
1225: }
1226:
1227: UINT32 debugger_get_ofs(const char *str)
1228: {
1229: char tmp[1024], *s;
1230:
1231: if(str == NULL || strlen(str) == 0) {
1232: return(0);
1233: }
1234: strcpy(tmp, str);
1235:
1236: if((s = strstr(tmp, ":")) != NULL) {
1237: // 0000:0000
1238: return(debugger_get_val(s + 1));
1239: }
1240: return(debugger_get_val(tmp));
1241: }
1242:
1243: void debugger_main()
1244: {
1245: telnet_command("\033[20h"); // cr-lf
1246:
1247: force_suspend = true;
1248: now_going = false;
1249: now_debugging = true;
1250: Sleep(100);
1251:
1252: if(!m_exit && !now_suspended) {
1253: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1254: telnet_printf("waiting until cpu is suspended...\n");
1255: }
1256: while(!m_exit && !now_suspended) {
1257: if(telnet_disconnected()) {
1258: break;
1259: }
1260: Sleep(10);
1261: }
1262:
1263: char buffer[8192];
1264:
1265: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1266: debugger_process_info(buffer);
1267: telnet_printf("%s", buffer);
1268: debugger_regs_info(buffer);
1269: telnet_printf("%s", buffer);
1270: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1271: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip);
1272: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1273: debugger_dasm(buffer, SREG(CS), m_eip);
1274: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1275: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1276:
1277: #define MAX_COMMAND_LEN 64
1278:
1279: char command[MAX_COMMAND_LEN + 1];
1280: char prev_command[MAX_COMMAND_LEN + 1] = {0};
1281:
1282: UINT32 data_seg = SREG(DS);
1283: UINT32 data_ofs = 0;
1284: UINT32 dasm_seg = SREG(CS);
1285: UINT32 dasm_ofs = m_eip;
1286:
1287: while(!m_exit) {
1288: telnet_printf("- ");
1289: command[0] = '\0';
1290:
1291: if(fi_debugger != NULL) {
1292: while(command[0] == '\0') {
1293: if(fgets(command, sizeof(command), fi_debugger) == NULL) {
1294: break;
1295: }
1296: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) {
1297: command[strlen(command) - 1] = '\0';
1298: }
1299: }
1300: if(command[0] != '\0') {
1301: telnet_command("%s\n", command);
1302: }
1303: }
1304: if(command[0] == '\0') {
1305: if(!telnet_gets(command, sizeof(command))) {
1306: break;
1307: }
1308: }
1309: if(command[0] == '\0') {
1310: strcpy(command, prev_command);
1311: } else {
1312: strcpy(prev_command, command);
1313: }
1314: if(fp_debugger != NULL) {
1315: fprintf(fp_debugger, "%s\n", command);
1316: }
1317:
1318: if(!m_exit && command[0] != 0) {
1319: char *params[32], *token = NULL;
1320: int num = 0;
1321:
1322: if((token = strtok(command, " ")) != NULL) {
1323: params[num++] = token;
1324: while(num < 32 && (token = strtok(NULL, " ")) != NULL) {
1325: params[num++] = token;
1326: }
1327: }
1328: if(stricmp(params[0], "D") == 0) {
1329: if(num <= 3) {
1330: if(num >= 2) {
1331: data_seg = debugger_get_seg(params[1], data_seg);
1332: data_ofs = debugger_get_ofs(params[1]);
1333: }
1334: UINT32 end_seg = data_seg;
1335: UINT32 end_ofs = data_ofs + 8 * 16 - 1;
1336: if(num == 3) {
1337: end_seg = debugger_get_seg(params[2], data_seg);
1338: end_ofs = debugger_get_ofs(params[2]);
1339: }
1340: UINT64 start_addr = (data_seg << 4) + data_ofs;
1341: UINT64 end_addr = (end_seg << 4) + end_ofs;
1342: // bool is_sjis = false;
1343:
1344: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) {
1345: if((addr & 0x0f) == 0) {
1346: if((data_ofs = addr - (data_seg << 4)) > 0xffff) {
1347: data_seg += 0x1000;
1348: data_ofs -= 0x10000;
1349: }
1350: telnet_printf("%06X:%04X ", data_seg, data_ofs);
1351: memset(buffer, 0, sizeof(buffer));
1352: }
1353: if(addr < start_addr || addr > end_addr) {
1354: telnet_printf(" ");
1355: buffer[addr & 0x0f] = ' ';
1356: } else {
1357: UINT8 data = debugger_read_byte(addr & ADDR_MASK);
1358: telnet_printf(" %02X", data);
1359: // if(is_sjis) {
1360: // buffer[addr & 0x0f] = data;
1361: // is_sjis = false;
1362: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) {
1363: // buffer[addr & 0x0f] = data;
1364: // is_sjis = true;
1365: // } else
1366: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) {
1367: buffer[addr & 0x0f] = data;
1368: } else {
1369: buffer[addr & 0x0f] = '.';
1370: }
1371: }
1372: if((addr & 0x0f) == 0x0f) {
1373: telnet_printf(" %s\n", buffer);
1374: }
1375: }
1376: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) {
1377: data_seg += 0x1000;
1378: data_ofs -= 0x10000;
1379: }
1380: prev_command[1] = '\0'; // remove parameters to dump continuously
1381: } else {
1382: telnet_printf("invalid parameter number\n");
1383: }
1384: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) {
1385: if(num >= 3) {
1386: UINT32 seg = debugger_get_seg(params[1], data_seg);
1387: UINT32 ofs = debugger_get_ofs(params[1]);
1388: for(int i = 2, j = 0; i < num; i++, j++) {
1389: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff);
1390: }
1391: } else {
1392: telnet_printf("invalid parameter number\n");
1393: }
1394: } else if(stricmp(params[0], "EW") == 0) {
1395: if(num >= 3) {
1396: UINT32 seg = debugger_get_seg(params[1], data_seg);
1397: UINT32 ofs = debugger_get_ofs(params[1]);
1398: for(int i = 2, j = 0; i < num; i++, j += 2) {
1399: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff);
1400: }
1401: } else {
1402: telnet_printf("invalid parameter number\n");
1403: }
1404: } else if(stricmp(params[0], "ED") == 0) {
1405: if(num >= 3) {
1406: UINT32 seg = debugger_get_seg(params[1], data_seg);
1407: UINT32 ofs = debugger_get_ofs(params[1]);
1408: for(int i = 2, j = 0; i < num; i++, j += 4) {
1409: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]));
1410: }
1411: } else {
1412: telnet_printf("invalid parameter number\n");
1413: }
1414: } else if(stricmp(params[0], "EA") == 0) {
1415: if(num >= 3) {
1416: UINT32 seg = debugger_get_seg(params[1], data_seg);
1417: UINT32 ofs = debugger_get_ofs(params[1]);
1418: strcpy(buffer, prev_command);
1419: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) {
1420: int len = strlen(token);
1421: for(int i = 0; i < len; i++) {
1422: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff);
1423: }
1424: } else {
1425: telnet_printf("invalid parameter\n");
1426: }
1427: } else {
1428: telnet_printf("invalid parameter number\n");
1429: }
1430: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) {
1431: if(num == 2) {
1432: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff);
1433: } else {
1434: telnet_printf("invalid parameter number\n");
1435: }
1436: } else if(stricmp(params[0], "IW") == 0) {
1437: if(num == 2) {
1438: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff);
1439: } else {
1440: telnet_printf("invalid parameter number\n");
1441: }
1442: } else if(stricmp(params[0], "ID") == 0) {
1443: if(num == 2) {
1444: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1])));
1445: } else {
1446: telnet_printf("invalid parameter number\n");
1447: }
1448: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) {
1449: if(num == 3) {
1450: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff);
1451: } else {
1452: telnet_printf("invalid parameter number\n");
1453: }
1454: } else if(stricmp(params[0], "OW") == 0) {
1455: if(num == 3) {
1456: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff);
1457: } else {
1458: telnet_printf("invalid parameter number\n");
1459: }
1460: } else if(stricmp(params[0], "OD") == 0) {
1461: if(num == 3) {
1462: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2]));
1463: } else {
1464: telnet_printf("invalid parameter number\n");
1465: }
1466: } else if(stricmp(params[0], "R") == 0) {
1467: if(num == 1) {
1468: debugger_regs_info(buffer);
1469: telnet_printf("%s", buffer);
1470: } else if(num == 3) {
1471: #if defined(HAS_I386)
1472: if(stricmp(params[1], "EAX") == 0) {
1473: REG32(EAX) = debugger_get_val(params[2]);
1474: } else if(stricmp(params[1], "EBX") == 0) {
1475: REG32(EBX) = debugger_get_val(params[2]);
1476: } else if(stricmp(params[1], "ECX") == 0) {
1477: REG32(ECX) = debugger_get_val(params[2]);
1478: } else if(stricmp(params[1], "EDX") == 0) {
1479: REG32(EDX) = debugger_get_val(params[2]);
1480: } else if(stricmp(params[1], "ESP") == 0) {
1481: REG32(ESP) = debugger_get_val(params[2]);
1482: } else if(stricmp(params[1], "EBP") == 0) {
1483: REG32(EBP) = debugger_get_val(params[2]);
1484: } else if(stricmp(params[1], "ESI") == 0) {
1485: REG32(ESI) = debugger_get_val(params[2]);
1486: } else if(stricmp(params[1], "EDI") == 0) {
1487: REG32(EDI) = debugger_get_val(params[2]);
1488: } else
1489: #endif
1490: if(stricmp(params[1], "AX") == 0) {
1491: REG16(AX) = debugger_get_val(params[2]);
1492: } else if(stricmp(params[1], "BX") == 0) {
1493: REG16(BX) = debugger_get_val(params[2]);
1494: } else if(stricmp(params[1], "CX") == 0) {
1495: REG16(CX) = debugger_get_val(params[2]);
1496: } else if(stricmp(params[1], "DX") == 0) {
1497: REG16(DX) = debugger_get_val(params[2]);
1498: } else if(stricmp(params[1], "SP") == 0) {
1499: REG16(SP) = debugger_get_val(params[2]);
1500: } else if(stricmp(params[1], "BP") == 0) {
1501: REG16(BP) = debugger_get_val(params[2]);
1502: } else if(stricmp(params[1], "SI") == 0) {
1503: REG16(SI) = debugger_get_val(params[2]);
1504: } else if(stricmp(params[1], "DI") == 0) {
1505: REG16(DI) = debugger_get_val(params[2]);
1506: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) {
1507: #if defined(HAS_I386)
1508: if(m_operand_size) {
1509: m_eip = debugger_get_val(params[2]);
1510: } else {
1511: m_eip = debugger_get_val(params[2]) & 0xffff;
1512: }
1513: CHANGE_PC(m_eip);
1514: #else
1515: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK;
1516: CHANGE_PC(m_pc);
1517: #endif
1518: } else if(stricmp(params[1], "AL") == 0) {
1519: REG8(AL) = debugger_get_val(params[2]);
1520: } else if(stricmp(params[1], "AH") == 0) {
1521: REG8(AH) = debugger_get_val(params[2]);
1522: } else if(stricmp(params[1], "BL") == 0) {
1523: REG8(BL) = debugger_get_val(params[2]);
1524: } else if(stricmp(params[1], "BH") == 0) {
1525: REG8(BH) = debugger_get_val(params[2]);
1526: } else if(stricmp(params[1], "CL") == 0) {
1527: REG8(CL) = debugger_get_val(params[2]);
1528: } else if(stricmp(params[1], "CH") == 0) {
1529: REG8(CH) = debugger_get_val(params[2]);
1530: } else if(stricmp(params[1], "DL") == 0) {
1531: REG8(DL) = debugger_get_val(params[2]);
1532: } else if(stricmp(params[1], "DH") == 0) {
1533: REG8(DH) = debugger_get_val(params[2]);
1534: } else {
1535: telnet_printf("unknown register %s\n", params[1]);
1536: }
1537: } else {
1538: telnet_printf("invalid parameter number\n");
1539: }
1540: } else if(stricmp(params[0], "S") == 0) {
1541: if(num >= 4) {
1542: UINT32 cur_seg = debugger_get_seg(params[1], data_seg);
1543: UINT32 cur_ofs = debugger_get_ofs(params[1]);
1544: UINT32 end_seg = debugger_get_seg(params[2], cur_seg);
1545: UINT32 end_ofs = debugger_get_ofs(params[2]);
1546: UINT8 list[32];
1547:
1548: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1549: list[j] = debugger_get_val(params[i]);
1550: }
1551: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) {
1552: bool found = true;
1553: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1554: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) {
1555: found = false;
1556: break;
1557: }
1558: }
1559: if(found) {
1560: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs);
1561: }
1562: if((cur_ofs += 1) > 0xffff) {
1563: cur_seg += 0x1000;
1564: cur_ofs -= 0x10000;
1565: }
1566: }
1567: } else {
1568: telnet_printf("invalid parameter number\n");
1569: }
1570: } else if(stricmp(params[0], "U") == 0) {
1571: if(num <= 3) {
1572: if(num >= 2) {
1573: dasm_seg = debugger_get_seg(params[1], dasm_seg);
1574: dasm_ofs = debugger_get_ofs(params[1]);
1575: }
1576: if(num == 3) {
1577: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg);
1578: UINT32 end_ofs = debugger_get_ofs(params[2]);
1579:
1580: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) {
1581: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1582: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1583: for(int i = 0; i < len; i++) {
1584: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1585: }
1586: for(int i = len; i < 8; i++) {
1587: telnet_printf(" ");
1588: }
1589: telnet_printf(" %s\n", buffer);
1590: if((dasm_ofs += len) > 0xffff) {
1591: dasm_seg += 0x1000;
1592: dasm_ofs -= 0x10000;
1593: }
1594: }
1595: } else {
1596: for(int i = 0; i < 16; i++) {
1597: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1598: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1599: for(int i = 0; i < len; i++) {
1600: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1601: }
1602: for(int i = len; i < 8; i++) {
1603: telnet_printf(" ");
1604: }
1605: telnet_printf(" %s\n", buffer);
1606: if((dasm_ofs += len) > 0xffff) {
1607: dasm_seg += 0x1000;
1608: dasm_ofs -= 0x10000;
1609: }
1610: }
1611: }
1612: prev_command[1] = '\0'; // remove parameters to disassemble continuously
1613: } else {
1614: telnet_printf("invalid parameter number\n");
1615: }
1616: } else if(stricmp(params[0], "H") == 0) {
1617: if(num == 3) {
1618: UINT32 l = debugger_get_val(params[1]);
1619: UINT32 r = debugger_get_val(params[2]);
1620: telnet_printf("%08X %08X\n", l + r, l - r);
1621: } else {
1622: telnet_printf("invalid parameter number\n");
1623: }
1624: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) {
1625: break_point_t *break_point_ptr;
1626: #define GET_BREAK_POINT_PTR() { \
1627: if(params[0][0] == 'R' || params[0][0] == 'r') { \
1628: break_point_ptr = &rd_break_point; \
1629: } else if(params[0][0] == 'W' || params[0][0] == 'w') { \
1630: break_point_ptr = &wr_break_point; \
1631: } else if(params[0][0] == 'I' || params[0][0] == 'i') { \
1632: break_point_ptr = &in_break_point; \
1633: } else if(params[0][0] == 'O' || params[0][0] == 'o') { \
1634: break_point_ptr = &out_break_point; \
1635: } else { \
1636: break_point_ptr = &break_point; \
1637: } \
1638: }
1639: GET_BREAK_POINT_PTR();
1640: if(num == 2) {
1641: UINT32 seg = 0;
1642: if(params[0][0] == 'R' || params[0][0] == 'r' || params[0][0] == 'W' || params[0][0] == 'w') {
1643: seg = debugger_get_seg(params[1], data_seg);
1644: } else {
1645: seg = debugger_get_seg(params[1], SREG(CS));
1646: }
1647: UINT32 ofs = debugger_get_ofs(params[1]);
1648: bool found = false;
1649: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1650: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) {
1651: break_point_ptr->table[i].addr = (seg << 4) + ofs;
1652: break_point_ptr->table[i].seg = seg;
1653: break_point_ptr->table[i].ofs = ofs;
1654: break_point_ptr->table[i].status = 1;
1655: found = true;
1656: }
1657: }
1658: if(!found) {
1659: telnet_printf("too many break points\n");
1660: }
1661: } else {
1662: telnet_printf("invalid parameter number\n");
1663: }
1664: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) {
1665: break_point_t *break_point_ptr;
1666: GET_BREAK_POINT_PTR();
1667: if(num == 2) {
1668: UINT32 addr = debugger_get_val(params[1]);
1669: bool found = false;
1670: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1671: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) {
1672: break_point_ptr->table[i].addr = addr;
1673: break_point_ptr->table[i].status = 1;
1674: found = true;
1675: }
1676: }
1677: if(!found) {
1678: telnet_printf("too many break points\n");
1679: }
1680: } else {
1681: telnet_printf("invalid parameter number\n");
1682: }
1683: } else if(stricmp(params[0], "BC") == 0 || stricmp(params[0], "RBC") == 0 || stricmp(params[0], "WBC") == 0 || stricmp(params[0], "IBC") == 0 || stricmp(params[0], "OBC") == 0) {
1684: break_point_t *break_point_ptr;
1685: GET_BREAK_POINT_PTR();
1686: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1687: memset(break_point_ptr, 0, sizeof(break_point_t));
1688: } else if(num >= 2) {
1689: for(int i = 1; i < num; i++) {
1690: int index = debugger_get_val(params[i]);
1691: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1692: telnet_printf("invalid index %x\n", index);
1693: } else {
1694: break_point_ptr->table[index - 1].addr = 0;
1695: break_point_ptr->table[index - 1].seg = 0;
1696: break_point_ptr->table[index - 1].ofs = 0;
1697: break_point_ptr->table[index - 1].status = 0;
1698: }
1699: }
1700: } else {
1701: telnet_printf("invalid parameter number\n");
1702: }
1703: } else if(stricmp(params[0], "BD") == 0 || stricmp(params[0], "RBD") == 0 || stricmp(params[0], "WBD") == 0 || stricmp(params[0], "IBD") == 0 || stricmp(params[0], "OBD") == 0 ||
1704: stricmp(params[0], "BE") == 0 || stricmp(params[0], "RBE") == 0 || stricmp(params[0], "WBE") == 0 || stricmp(params[0], "IBE") == 0 || stricmp(params[0], "OBE") == 0) {
1705: break_point_t *break_point_ptr;
1706: GET_BREAK_POINT_PTR();
1707: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1708: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1709: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1710: if(break_point_ptr->table[i].status != 0) {
1711: break_point_ptr->table[i].status = enabled ? 1 : -1;
1712: }
1713: }
1714: } else if(num >= 2) {
1715: for(int i = 1; i < num; i++) {
1716: int index = debugger_get_val(params[i]);
1717: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1718: telnet_printf("invalid index %x\n", index);
1719: } else if(break_point_ptr->table[index - 1].status == 0) {
1720: telnet_printf("break point %x is null\n", index);
1721: } else {
1722: break_point_ptr->table[index - 1].status = enabled ? 1 : -1;
1723: }
1724: }
1725: } else {
1726: telnet_printf("invalid parameter number\n");
1727: }
1728: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) {
1729: break_point_t *break_point_ptr;
1730: GET_BREAK_POINT_PTR();
1731: if(num == 1) {
1732: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1733: if(break_point_ptr->table[i].status) {
1734: telnet_printf("%d %c %04X:%04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].seg, break_point_ptr->table[i].ofs);
1735: }
1736: }
1737: } else {
1738: telnet_printf("invalid parameter number\n");
1739: }
1740: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) {
1741: break_point_t *break_point_ptr;
1742: GET_BREAK_POINT_PTR();
1743: if(num == 1) {
1744: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1745: if(break_point_ptr->table[i].status) {
1746: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr);
1747: }
1748: }
1749: } else {
1750: telnet_printf("invalid parameter number\n");
1751: }
1752: } else if(stricmp(params[0], "INTBP") == 0) {
1753: if(num >= 2 && num <= 4) {
1754: int int_num = debugger_get_val(params[1]);
1755: UINT8 ah = 0, ah_registered = 0;
1756: UINT8 al = 0, al_registered = 0;
1757: if(num >= 3) {
1758: ah = debugger_get_val(params[2]);
1759: ah_registered = 1;
1760: }
1761: if(num == 4) {
1762: al = debugger_get_val(params[3]);
1763: al_registered = 1;
1764: }
1765: bool found = false;
1766: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1767: if(int_break_point.table[i].status == 0 || (
1768: int_break_point.table[i].int_num == int_num &&
1769: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered &&
1770: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) {
1771: int_break_point.table[i].int_num = int_num;
1772: int_break_point.table[i].ah = ah;
1773: int_break_point.table[i].ah_registered = ah_registered;
1774: int_break_point.table[i].al = al;
1775: int_break_point.table[i].al_registered = al_registered;
1776: int_break_point.table[i].status = 1;
1777: found = true;
1778: }
1779: }
1780: if(!found) {
1781: telnet_printf("too many break points\n");
1782: }
1783: } else {
1784: telnet_printf("invalid parameter number\n");
1785: }
1786: } else if(stricmp(params[0], "INTBC") == 0) {
1787: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1788: memset(&int_break_point, 0, sizeof(int_break_point_t));
1789: } else if(num >= 2) {
1790: for(int i = 1; i < num; i++) {
1791: int index = debugger_get_val(params[i]);
1792: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1793: telnet_printf("invalid index %x\n", index);
1794: } else {
1795: int_break_point.table[index - 1].int_num = 0;
1796: int_break_point.table[index - 1].ah = 0;
1797: int_break_point.table[index - 1].ah_registered = 0;
1798: int_break_point.table[index - 1].al = 0;
1799: int_break_point.table[index - 1].al_registered = 0;
1800: int_break_point.table[index - 1].status = 0;
1801: }
1802: }
1803: } else {
1804: telnet_printf("invalid parameter number\n");
1805: }
1806: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) {
1807: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1808: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1809: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1810: if(int_break_point.table[i].status != 0) {
1811: int_break_point.table[i].status = enabled ? 1 : -1;
1812: }
1813: }
1814: } else if(num >= 2) {
1815: for(int i = 1; i < num; i++) {
1816: int index = debugger_get_val(params[i]);
1817: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1818: telnet_printf("invalid index %x\n", index);
1819: } else if(int_break_point.table[index - 1].status == 0) {
1820: telnet_printf("break point %x is null\n", index);
1821: } else {
1822: int_break_point.table[index - 1].status = enabled ? 1 : -1;
1823: }
1824: }
1825: } else {
1826: telnet_printf("invalid parameter number\n");
1827: }
1828: } else if(stricmp(params[0], "INTBL") == 0) {
1829: if(num == 1) {
1830: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1831: if(int_break_point.table[i].status) {
1832: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num);
1833: if(int_break_point.table[i].ah_registered) {
1834: telnet_printf(" %02X", int_break_point.table[i].ah);
1835: }
1836: if(int_break_point.table[i].al_registered) {
1837: telnet_printf(" %02X", int_break_point.table[i].al);
1838: }
1839: telnet_printf("\n");
1840: }
1841: }
1842: } else {
1843: telnet_printf("invalid parameter number\n");
1844: }
1845: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) {
1846: if(num == 1 || num == 2) {
1847: break_point_t break_point_stored;
1848: bool break_points_stored = false;
1849:
1850: if(stricmp(params[0], "P") == 0) {
1851: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1852: memset(&break_point, 0, sizeof(break_point_t));
1853: break_points_stored = true;
1854:
1855: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip);
1856: break_point.table[0].status = 1;
1857: } else if(num >= 2) {
1858: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1859: memset(&break_point, 0, sizeof(break_point_t));
1860: break_points_stored = true;
1861:
1862: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1863: UINT32 ofs = debugger_get_ofs(params[1]);
1864: break_point.table[0].addr = (seg << 4) + ofs;
1865: break_point.table[0].seg = seg;
1866: break_point.table[0].ofs = ofs;
1867: break_point.table[0].status = 1;
1868: }
1869: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1870: now_going = true;
1871: now_suspended = false;
1872:
1873: telnet_command("\033[2l"); // key unlock
1874: while(!m_exit && !now_suspended) {
1875: if(telnet_kbhit()) {
1876: break;
1877: }
1878: Sleep(10);
1879: }
1880: now_going = false;
1881: telnet_command("\033[2h"); // key lock
1882:
1883: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1884: Sleep(100);
1885: if(!m_exit && !now_suspended) {
1886: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1887: telnet_printf("waiting until cpu is suspended...\n");
1888: }
1889: }
1890: while(!m_exit && !now_suspended) {
1891: if(telnet_disconnected()) {
1892: break;
1893: }
1894: Sleep(10);
1895: }
1896: dasm_seg = SREG(CS);
1897: dasm_ofs = m_eip;
1898:
1899: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1900: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1901: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1902:
1903: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1904: debugger_regs_info(buffer);
1905: telnet_printf("%s", buffer);
1906:
1907: if(break_point.hit) {
1908: if(stricmp(params[0], "G") == 0 && num == 1) {
1909: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1910: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1911: }
1912: } else if(rd_break_point.hit) {
1913: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1914: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1915: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1916: m_prev_cs, m_prev_eip);
1917: } else if(wr_break_point.hit) {
1918: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1919: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1920: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1921: m_prev_cs, m_prev_eip);
1922: } else if(in_break_point.hit) {
1923: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1924: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1925: in_break_point.table[in_break_point.hit - 1].addr,
1926: m_prev_cs, m_prev_eip);
1927: } else if(out_break_point.hit) {
1928: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1929: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1930: out_break_point.table[out_break_point.hit - 1].addr,
1931: m_prev_cs, m_prev_eip);
1932: } else if(int_break_point.hit) {
1933: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1934: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1935: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1936: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1937: }
1938: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1939: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1940: }
1941: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1942: } else {
1943: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1944: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1945: }
1946: if(break_points_stored) {
1947: memcpy(&break_point, &break_point_stored, sizeof(break_point_t));
1948: }
1949: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1950: debugger_dasm(buffer, SREG(CS), m_eip);
1951: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1952: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1953: } else {
1954: telnet_printf("invalid parameter number\n");
1955: }
1956: } else if(stricmp(params[0], "T") == 0) {
1957: if(num == 1 || num == 2) {
1958: int steps = 1;
1959: if(num >= 2) {
1960: steps = debugger_get_val(params[1]);
1961: }
1962:
1963: telnet_command("\033[2l"); // key unlock
1964: while(steps-- > 0) {
1965: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1966: now_going = false;
1967: now_suspended = false;
1968:
1969: while(!m_exit && !now_suspended) {
1970: if(telnet_disconnected()) {
1971: break;
1972: }
1973: Sleep(10);
1974: }
1975: dasm_seg = SREG(CS);
1976: dasm_ofs = m_eip;
1977:
1978: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1979: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1980: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1981:
1982: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1983: debugger_regs_info(buffer);
1984: telnet_printf("%s", buffer);
1985:
1986: if(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit || telnet_kbhit()) {
1987: break;
1988: }
1989: }
1990: telnet_command("\033[2h"); // key lock
1991:
1992: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1993: Sleep(100);
1994: if(!m_exit && !now_suspended) {
1995: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1996: telnet_printf("waiting until cpu is suspended...\n");
1997: }
1998: }
1999: while(!m_exit && !now_suspended) {
2000: if(telnet_disconnected()) {
2001: break;
2002: }
2003: Sleep(10);
2004: }
2005: if(break_point.hit) {
2006: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
2007: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
2008: } else if(rd_break_point.hit) {
2009: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
2010: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
2011: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
2012: m_prev_cs, m_prev_eip);
2013: } else if(wr_break_point.hit) {
2014: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
2015: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
2016: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
2017: m_prev_cs, m_prev_eip);
2018: } else if(in_break_point.hit) {
2019: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
2020: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
2021: in_break_point.table[in_break_point.hit - 1].addr,
2022: m_prev_cs, m_prev_eip);
2023: } else if(out_break_point.hit) {
2024: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
2025: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
2026: out_break_point.table[out_break_point.hit - 1].addr,
2027: m_prev_cs, m_prev_eip);
2028: } else if(int_break_point.hit) {
2029: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
2030: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
2031: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
2032: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
2033: }
2034: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
2035: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
2036: }
2037: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
2038: } else if(steps > 0) {
2039: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
2040: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
2041: }
2042: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
2043: debugger_dasm(buffer, SREG(CS), m_eip);
2044: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
2045: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
2046: } else {
2047: telnet_printf("invalid parameter number\n");
2048: }
2049: } else if(stricmp(params[0], "Q") == 0) {
2050: break;
2051: } else if(stricmp(params[0], "X") == 0) {
2052: debugger_process_info(buffer);
2053: telnet_printf("%s", buffer);
2054: } else if(stricmp(params[0], ">") == 0) {
2055: if(num == 2) {
2056: if(fp_debugger != NULL) {
2057: fclose(fp_debugger);
2058: fp_debugger = NULL;
2059: }
2060: fp_debugger = fopen(params[1], "w");
2061: } else {
2062: telnet_printf("invalid parameter number\n");
2063: }
2064: } else if(stricmp(params[0], "<") == 0) {
2065: if(num == 2) {
2066: if(fi_debugger != NULL) {
2067: fclose(fi_debugger);
2068: fi_debugger = NULL;
2069: }
2070: fi_debugger = fopen(params[1], "r");
2071: } else {
2072: telnet_printf("invalid parameter number\n");
2073: }
2074: } else if(stricmp(params[0], "?") == 0) {
2075: telnet_printf("D [<start> [<end>]] - dump memory\n");
2076: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n");
2077: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n");
2078: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n");
2079: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n");
2080:
2081: telnet_printf("R - show registers\n");
2082: telnet_printf("R <reg> <value> - edit register\n");
2083: telnet_printf("S <start> <end> <list> - search\n");
2084: telnet_printf("U [<start> [<end>]] - unassemble\n");
2085:
2086: telnet_printf("H <value> <value> - hexadd\n");
2087:
2088: telnet_printf("BP <address> - set breakpoint\n");
2089: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n");
2090: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n");
2091: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n");
2092: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n");
2093: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n");
2094:
2095: telnet_printf("G - go (press enter key to break)\n");
2096: telnet_printf("G <address> - go and break at address\n");
2097: telnet_printf("P - trace one opcode (step over)\n");
2098: telnet_printf("T [<count>] - trace (step in)\n");
2099: telnet_printf("Q - quit\n");
2100: telnet_printf("X - show dos process info\n");
2101:
2102: telnet_printf("> <filename> - output logfile\n");
2103: telnet_printf("< <filename> - input commands from file\n");
2104:
2105: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n");
2106: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n");
2107: } else {
2108: telnet_printf("unknown command %s\n", params[0]);
2109: }
2110: }
2111: }
2112: if(fp_debugger != NULL) {
2113: fclose(fp_debugger);
2114: fp_debugger = NULL;
2115: }
2116: if(fi_debugger != NULL) {
2117: fclose(fi_debugger);
2118: fi_debugger = NULL;
2119: }
2120: now_debugging = now_going = now_suspended = force_suspend = false;
2121: closesocket(cli_socket);
2122: }
2123:
2124: const char *debugger_get_ttermpro_path()
2125: {
2126: static char path[MAX_PATH] = {0};
2127:
2128: if(getenv("ProgramFiles")) {
2129: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles"));
2130: }
2131: return(path);
2132: }
2133:
2134: const char *debugger_get_ttermpro_x86_path()
2135: {
2136: static char path[MAX_PATH] = {0};
2137:
2138: if(getenv("ProgramFiles(x86)")) {
2139: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)"));
2140: }
2141: return(path);
2142: }
2143:
2144: const char *debugger_get_putty_path()
2145: {
2146: static char path[MAX_PATH] = {0};
2147:
2148: if(getenv("ProgramFiles")) {
2149: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles"));
2150: }
2151: return(path);
2152: }
2153:
2154: const char *debugger_get_putty_x86_path()
2155: {
2156: static char path[MAX_PATH] = {0};
2157:
2158: if(getenv("ProgramFiles(x86)")) {
2159: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)"));
2160: }
2161: return(path);
2162: }
2163:
2164: const char *debugger_get_telnet_path()
2165: {
2166: // NOTE: When you run 32bit version of msdos.exe on Windows x64,
2167: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64.
2168: // But 32bit version of telnet.exe will not be installed in SysWOW64
2169: // and 64bit version of telnet.exe will be installed in System32.
2170: static char path[MAX_PATH] = {0};
2171:
2172: if(getenv("windir") != NULL) {
2173: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir"));
2174: }
2175: return(path);
2176: }
2177:
2178: DWORD WINAPI debugger_thread(LPVOID)
2179: {
2180: WSADATA was_data;
2181: struct sockaddr_in svr_addr;
2182: struct sockaddr_in cli_addr;
2183: int cli_addr_len = sizeof(cli_addr);
2184: int port = 23;
2185: int bind_stat = SOCKET_ERROR;
2186: struct timeval timeout;
2187:
2188: WSAStartup(MAKEWORD(2,0), &was_data);
2189:
2190: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
2191: memset(&svr_addr, 0, sizeof(svr_addr));
2192: svr_addr.sin_family = AF_INET;
2193: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
2194:
2195: while(!m_exit && port < 10000) {
2196: svr_addr.sin_port = htons(port);
2197: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
2198: break;
2199: } else {
2200: port = (port == 23) ? 9000 : (port + 1);
2201: }
2202: }
2203: if(bind_stat == 0) {
2204: timeout.tv_sec = 1;
2205: timeout.tv_usec = 0;
2206: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
2207:
2208: listen(svr_socket, 1);
2209:
2210: char command[MAX_PATH] = {0};
2211: STARTUPINFOA si;
2212: PROCESS_INFORMATION pi;
2213:
2214: if(_access(debugger_get_ttermpro_path(), 0) == 0) {
2215: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port);
2216: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) {
2217: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port);
2218: } else if(_access(debugger_get_putty_path(), 0) == 0) {
2219: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port);
2220: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) {
2221: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port);
2222: } else if(_access(debugger_get_telnet_path(), 0) == 0) {
2223: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port);
2224: }
2225: if(command[0] != '\0') {
2226: memset(&si, 0, sizeof(STARTUPINFOA));
2227: memset(&pi, 0, sizeof(PROCESS_INFORMATION));
2228: CreateProcessA(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
2229: }
2230:
2231: while(!m_exit) {
2232: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
2233: u_long val = 1;
2234: ioctlsocket(cli_socket, FIONBIO, &val);
2235: debugger_main();
2236: }
2237: }
2238: }
2239: }
2240: WSACleanup();
2241: return(0);
2242: }
2243: #endif
2244:
2245: /* ----------------------------------------------------------------------------
2246: main
2247: ---------------------------------------------------------------------------- */
2248:
2249: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
2250: {
2251: if(dwCtrlType == CTRL_BREAK_EVENT) {
2252: if(key_buf_char != NULL && key_buf_scan != NULL) {
2253: #ifdef USE_SERVICE_THREAD
2254: EnterCriticalSection(&key_buf_crit_sect);
2255: #endif
2256: pcbios_clear_key_buffer();
2257: #ifdef USE_SERVICE_THREAD
2258: LeaveCriticalSection(&key_buf_crit_sect);
2259: #endif
2260: }
2261: // key_code = key_recv = 0;
2262: return TRUE;
2263: } else if(dwCtrlType == CTRL_C_EVENT) {
2264: return TRUE;
2265: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
2266: // this program will be terminated abnormally, do minimum end process
2267: exit_handler();
2268: exit(1);
2269: }
2270: return FALSE;
2271: }
2272:
2273: void exit_handler()
2274: {
2275: if(temp_file_created) {
2276: DeleteFileA(temp_file_path);
2277: temp_file_created = false;
2278: }
2279: if(key_buf_char != NULL) {
2280: key_buf_char->release();
2281: delete key_buf_char;
2282: key_buf_char = NULL;
2283: }
2284: if(key_buf_scan != NULL) {
2285: key_buf_scan->release();
2286: delete key_buf_scan;
2287: key_buf_scan = NULL;
2288: }
2289: if(key_buf_data != NULL) {
2290: key_buf_data->release();
2291: delete key_buf_data;
2292: key_buf_data = NULL;
2293: }
2294: #ifdef SUPPORT_XMS
2295: msdos_xms_release();
2296: #endif
2297: hardware_release();
2298: }
2299:
2300: #ifdef USE_VRAM_THREAD
2301: DWORD WINAPI vram_thread(LPVOID)
2302: {
2303: while(!m_exit) {
2304: EnterCriticalSection(&vram_crit_sect);
2305: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
2306: vram_flush_char();
2307: }
2308: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
2309: vram_flush_attr();
2310: }
2311: vram_last_length_char = vram_length_char;
2312: vram_last_length_attr = vram_length_attr;
2313: LeaveCriticalSection(&vram_crit_sect);
2314: // this is about half the maximum keyboard repeat rate - any
2315: // lower tends to be jerky, any higher misses updates
2316: Sleep(15);
2317: }
2318: return 0;
2319: }
2320: #endif
2321:
2322: long get_section_in_exec_file(FILE *fp, const char *name)
2323: {
2324: UINT8 header[0x400];
2325:
2326: long position = ftell(fp);
2327: fseek(fp, 0, SEEK_SET);
2328: fread(header, sizeof(header), 1, fp);
2329: fseek(fp, position, SEEK_SET);
2330:
2331: try {
2332: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2333: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2334: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2335: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2336: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2337: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2338:
2339: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
2340: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
2341: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
2342: return(sectionHeader->PointerToRawData);
2343: }
2344: }
2345: } catch(...) {
2346: }
2347: return(0);
2348: }
2349:
2350: bool is_started_from_command_prompt()
2351: {
2352: bool result = false;
2353: HMODULE hLibrary = LoadLibraryA("Kernel32.dll");
2354:
2355: if(hLibrary) {
2356: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
2357: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
2358: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
2359: if(lpfnGetConsoleProcessList) { // Windows XP or later
2360: DWORD pl;
2361: result = (lpfnGetConsoleProcessList(&pl, 1) > 1);
2362: FreeLibrary(hLibrary);
2363: return(result);
2364: }
2365: FreeLibrary(hLibrary);
2366: }
2367:
2368: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2369: if(hSnapshot != INVALID_HANDLE_VALUE) {
2370: DWORD dwParentProcessID = 0;
2371: PROCESSENTRY32 pe32;
2372: pe32.dwSize = sizeof(PROCESSENTRY32);
2373: if(Process32First(hSnapshot, &pe32)) {
2374: do {
2375: if(pe32.th32ProcessID == GetCurrentProcessId()) {
2376: dwParentProcessID = pe32.th32ParentProcessID;
2377: break;
2378: }
2379: } while(Process32Next(hSnapshot, &pe32));
2380: }
2381: CloseHandle(hSnapshot);
2382: if(dwParentProcessID != 0) {
2383: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
2384: if(hProcess != NULL) {
2385: HMODULE hMod;
2386: DWORD cbNeeded;
2387: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
2388: char module_name[MAX_PATH];
2389: if(GetModuleBaseNameA(hProcess, hMod, module_name, sizeof(module_name))) {
2390: result = (_strnicmp(module_name, "cmd.exe", 7) == 0);
2391: }
2392: }
2393: CloseHandle(hProcess);
2394: }
2395: }
2396: }
2397: return(result);
2398: }
2399:
2400: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
2401: {
2402: HMODULE hLibrary = LoadLibraryA("Kernel32.dll");
2403:
2404: if(hLibrary) {
2405: typedef ULONGLONG (WINAPI* VerSetConditionMaskFunction)(ULONGLONG, DWORD, BYTE);
2406: typedef BOOL(WINAPI* VerifyVersionInfoFunction)(LPOSVERSIONINFOEXA, DWORD, DWORDLONG);
2407:
2408: VerSetConditionMaskFunction lpfnVerSetConditionMask = reinterpret_cast<VerSetConditionMaskFunction>(::GetProcAddress(hLibrary, "VerSetConditionMask"));
2409: VerifyVersionInfoFunction lpfnVerifyVersionInfo = reinterpret_cast<VerifyVersionInfoFunction>(::GetProcAddress(hLibrary, "VerifyVersionInfoA"));
2410:
2411: if(lpfnVerSetConditionMask && lpfnVerifyVersionInfo) { // Windows 2000 or later
2412: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
2413: OSVERSIONINFOEXA osvi;
2414: DWORDLONG dwlConditionMask = 0;
2415: int op = VER_GREATER_EQUAL;
2416:
2417: // Initialize the OSVERSIONINFOEXA structure.
2418: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXA));
2419: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
2420: osvi.dwMajorVersion = dwMajorVersion;
2421: osvi.dwMinorVersion = dwMinorVersion;
2422: osvi.wServicePackMajor = wServicePackMajor;
2423: osvi.wServicePackMinor = wServicePackMinor;
2424:
2425: // Initialize the condition mask.
2426: #define MY_VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=lpfnVerSetConditionMask((_m_),(_t_),(_c_)))
2427:
2428: MY_VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
2429: MY_VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
2430: MY_VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
2431: MY_VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
2432:
2433: // Perform the test.
2434: BOOL result = lpfnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
2435: FreeLibrary(hLibrary);
2436: return(result);
2437: }
2438: FreeLibrary(hLibrary);
2439: }
2440:
2441: OSVERSIONINFOA osvi;
2442: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2443:
2444: if(GetVersionExA((LPOSVERSIONINFOA)&osvi)) {
2445: if(osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
2446: return(false);
2447: } else if(osvi.dwMajorVersion > dwMajorVersion) {
2448: return(true);
2449: } else if(osvi.dwMajorVersion < dwMajorVersion) {
2450: return(false);
2451: } else if(osvi.dwMinorVersion > dwMinorVersion) {
2452: return(true);
2453: } else if(osvi.dwMinorVersion < dwMinorVersion) {
2454: return(false);
2455: }
2456: // FIXME: check wServicePackMajor and wServicePackMinor :-(
2457: return(true);
2458: }
2459: return(false);
2460: }
2461:
2462: HWND get_console_window_handle()
2463: {
2464: static HWND hwndFound = 0;
2465:
2466: if(hwndFound == 0) {
2467: // https://support.microsoft.com/en-us/help/124103/how-to-obtain-a-console-window-handle-hwnd
2468: char pszNewWindowTitle[1024];
2469: char pszOldWindowTitle[1024];
2470:
2471: GetConsoleTitleA(pszOldWindowTitle, 1024);
2472: wsprintfA(pszNewWindowTitle, "%d/%d", GetTickCount(), GetCurrentProcessId());
2473: SetConsoleTitleA(pszNewWindowTitle);
2474: Sleep(100);
2475: hwndFound = FindWindowA(NULL, pszNewWindowTitle);
2476: SetConsoleTitleA(pszOldWindowTitle);
2477: }
2478: return hwndFound;
2479: }
2480:
2481: HDC get_console_window_device_context()
2482: {
2483: return GetDC(get_console_window_handle());
2484: }
2485:
2486: bool get_console_font_size(int *width, int *height)
2487: {
2488: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
2489: bool result = false;
2490:
2491: if(is_winxp_or_later) {
2492: HMODULE hLibrary = LoadLibraryA("Kernel32.dll");
2493: if(hLibrary) {
2494: typedef BOOL (WINAPI* GetCurrentConsoleFontFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFO);
2495: GetCurrentConsoleFontFunction lpfnGetCurrentConsoleFont = reinterpret_cast<GetCurrentConsoleFontFunction>(::GetProcAddress(hLibrary, "GetCurrentConsoleFont"));
2496: if(lpfnGetCurrentConsoleFont) { // Windows XP or later
2497: CONSOLE_FONT_INFO fi;
2498: if(lpfnGetCurrentConsoleFont(hStdout, FALSE, &fi) != 0) {
2499: *width = fi.dwFontSize.X;
2500: *height = fi.dwFontSize.Y;
2501: result = true;
2502: }
2503: }
2504: FreeLibrary(hLibrary);
2505: }
2506: } else {
2507: CONSOLE_SCREEN_BUFFER_INFO csbi;
2508: RECT rect;
2509: if(GetConsoleScreenBufferInfo(hStdout, &csbi) && GetClientRect(get_console_window_handle(), &rect)) {
2510: int cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
2511: int rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2512: *width = rect.right / cols;
2513: *height = rect.bottom / rows;
2514: result = true;
2515: }
2516: }
2517: return(result);
2518: }
2519:
2520: bool set_console_font_size(int width, int height)
2521: {
2522: // http://d.hatena.ne.jp/aharisu/20090427/1240852598
2523: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
2524: bool result = false;
2525: HMODULE hLibrary = LoadLibraryA("Kernel32.dll");
2526:
2527: if(hLibrary) {
2528: CONSOLE_SCREEN_BUFFER_INFO csbi;
2529: RECT rect;
2530: GetConsoleScreenBufferInfo(hStdout, &csbi);
2531: int cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
2532: int rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2533:
2534: typedef BOOL (WINAPI* GetConsoleFontInfoFunction)(HANDLE, BOOL, DWORD, PCONSOLE_FONT_INFO);
2535: typedef DWORD (WINAPI* GetNumberOfConsoleFontsFunction)(VOID);
2536: typedef COORD (WINAPI* GetConsoleFontSizeFunction)(HANDLE, DWORD);
2537: typedef BOOL (WINAPI* SetConsoleFontFunction)(HANDLE, DWORD);
2538: typedef BOOL (WINAPI* GetCurrentConsoleFontFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFO);
2539: typedef BOOL (WINAPI* GetCurrentConsoleFontExFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX);
2540: typedef BOOL (WINAPI* SetCurrentConsoleFontExFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX);
2541:
2542: GetConsoleFontInfoFunction lpfnGetConsoleFontInfo = reinterpret_cast<GetConsoleFontInfoFunction>(::GetProcAddress(hLibrary, "GetConsoleFontInfo"));
2543: GetNumberOfConsoleFontsFunction lpfnGetNumberOfConsoleFonts = reinterpret_cast<GetNumberOfConsoleFontsFunction>(::GetProcAddress(hLibrary, "GetNumberOfConsoleFonts"));
2544: GetConsoleFontSizeFunction lpfnGetConsoleFontSize = reinterpret_cast<GetConsoleFontSizeFunction>(::GetProcAddress(hLibrary, "GetConsoleFontSize"));
2545: SetConsoleFontFunction lpfnSetConsoleFont = reinterpret_cast<SetConsoleFontFunction>(::GetProcAddress(hLibrary, "SetConsoleFont"));
2546: GetCurrentConsoleFontFunction lpfnGetCurrentConsoleFont = reinterpret_cast<GetCurrentConsoleFontFunction>(::GetProcAddress(hLibrary, "GetCurrentConsoleFont"));
2547: GetCurrentConsoleFontExFunction lpfnGetCurrentConsoleFontEx = reinterpret_cast<GetCurrentConsoleFontExFunction>(::GetProcAddress(hLibrary, "GetCurrentConsoleFontEx"));
2548: SetCurrentConsoleFontExFunction lpfnSetCurrentConsoleFontEx = reinterpret_cast<SetCurrentConsoleFontExFunction>(::GetProcAddress(hLibrary, "SetCurrentConsoleFontEx"));
2549:
2550: if(lpfnGetConsoleFontInfo && lpfnGetNumberOfConsoleFonts && lpfnSetConsoleFont) { // Windows 2000 or later
2551: DWORD dwFontNum = lpfnGetNumberOfConsoleFonts();
2552: if(dwFontNum) {
2553: CONSOLE_FONT_INFO* fonts = (CONSOLE_FONT_INFO*)malloc(sizeof(CONSOLE_FONT_INFO) * dwFontNum);
2554: lpfnGetConsoleFontInfo(hStdout, FALSE, dwFontNum, fonts);
2555: for(int i = 0; i < dwFontNum; i++) {
2556: fonts[i].dwFontSize = lpfnGetConsoleFontSize(hStdout, fonts[i].nFont);
2557: if(fonts[i].dwFontSize.X == width && fonts[i].dwFontSize.Y == height) {
2558: if(lpfnSetConsoleFont(hStdout, fonts[i].nFont)) {
2559: if(is_winxp_or_later && lpfnGetCurrentConsoleFont) { // Windows XP or later
2560: CONSOLE_FONT_INFO fi;
2561: if(lpfnGetCurrentConsoleFont(hStdout, FALSE, &fi)) {
2562: if(fonts[i].dwFontSize.X == fi.dwFontSize.X && fonts[i].dwFontSize.Y == fi.dwFontSize.Y) {
2563: result = true;
2564: break;
2565: }
2566: }
2567: } else {
2568: Sleep(10);
2569: if(GetClientRect(get_console_window_handle(), &rect)) {
2570: if(fonts[i].dwFontSize.X * cols == rect.right && fonts[i].dwFontSize.Y * rows == rect.bottom) {
2571: result = true;
2572: break;
2573: }
2574: }
2575: }
2576: }
2577: }
2578: }
2579: free(fonts);
2580: } else if(lpfnGetCurrentConsoleFontEx && lpfnSetCurrentConsoleFontEx) {
2581: // for Windows10 enhanced command prompt
2582: CONSOLE_FONT_INFOEX fi_old, fi_new;
2583: fi_old.cbSize = sizeof(CONSOLE_FONT_INFOEX);
2584: if(lpfnGetCurrentConsoleFontEx(hStdout, FALSE, &fi_old)) {
2585: fi_new = fi_old;
2586: fi_new.dwFontSize.X = width;
2587: fi_new.dwFontSize.Y = height;
2588: if(lpfnSetCurrentConsoleFontEx(hStdout, FALSE, &fi_new)) {
2589: lpfnGetCurrentConsoleFontEx(hStdout, FALSE, &fi_new);
2590: if(fi_new.dwFontSize.X == width && fi_new.dwFontSize.Y == height) {
2591: result = true;
2592: } else {
2593: lpfnSetCurrentConsoleFontEx(hStdout, FALSE, &fi_old);
2594: }
2595: }
2596: }
2597: }
2598: }
2599: FreeLibrary(hLibrary);
2600: }
2601: return(result);
2602: }
2603:
2604: bool is_cursor_blink_off()
2605: {
2606: static int result = -1;
2607: HKEY hKey;
2608: char chData[64];
2609: DWORD dwSize = sizeof(chData);
2610:
2611: if(result == -1) {
2612: result = 0;
2613: if(RegOpenKeyExA(HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
2614: if(RegQueryValueExA(hKey, "CursorBlinkRate", NULL, NULL, (LPBYTE)chData, &dwSize) == ERROR_SUCCESS) {
2615: if(strncmp(chData, "-1", 2) == 0) {
2616: result = 1;
2617: }
2618: }
2619: RegCloseKey(hKey);
2620: }
2621: }
2622: return(result != 0);
2623: }
2624:
2625: void get_sio_port_numbers()
2626: {
2627: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
2628: HDEVINFO hDevInfo = 0;
2629: HKEY hKey = 0;
2630: if((hDevInfo = SetupDiGetClassDevsA(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
2631: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
2632: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
2633: char chData[256];
2634: DWORD dwType = 0;
2635: DWORD dwSize = sizeof(chData);
2636: int port_number = 0;
2637:
2638: if(RegQueryValueExA(hKey, "PortName", NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
2639: if(_strnicmp(chData, "COM", 3) == 0) {
2640: port_number = atoi(chData + 3);
2641: }
2642: }
2643: RegCloseKey(hKey);
2644:
2645: 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) {
2646: continue;
2647: }
2648: if(sio_port_number[0] == 0) {
2649: sio_port_number[0] = port_number;
2650: } else if(sio_port_number[1] == 0) {
2651: sio_port_number[1] = port_number;
2652: } else if(sio_port_number[2] == 0) {
2653: sio_port_number[2] = port_number;
2654: } else if(sio_port_number[3] == 0) {
2655: sio_port_number[3] = port_number;
2656: }
2657: if(sio_port_number[0] != 0 && sio_port_number[1] != 0 && sio_port_number[2] != 0 && sio_port_number[3] != 0) {
2658: break;
2659: }
2660: }
2661: }
2662: }
2663: }
2664:
2665: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
2666:
2667: int main(int argc, char *argv[], char *envp[])
2668: {
2669: int arg_offset = 0;
2670: int standard_env = 0;
2671: int buf_width = 0, buf_height = 0;
2672: bool get_console_info_success = false;
2673: bool get_console_font_success = false;
2674: bool screen_size_changed = false;
2675:
2676: char path[MAX_PATH], full[MAX_PATH], *name = NULL;
2677: GetModuleFileNameA(NULL, path, MAX_PATH);
2678: GetFullPathNameA(path, MAX_PATH, full, &name);
2679:
2680: char dummy_argv_0[] = "msdos.exe";
2681: char dummy_argv_1[MAX_PATH];
2682: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
2683: char new_exec_file[MAX_PATH];
2684: bool convert_cmd_file = false;
2685: unsigned int code_page = 0;
2686:
2687: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
2688: // check if command file is embedded to this execution file
2689: // if this execution file name is msdos.exe, don't check
2690: FILE* fp = fopen(full, "rb");
2691: long offset = get_section_in_exec_file(fp, ".msdos");
2692: if(offset != 0) {
2693: UINT8 buffer[16];
2694: fseek(fp, offset, SEEK_SET);
2695: fread(buffer, sizeof(buffer), 1, fp);
2696:
2697: // restore flags
2698: stay_busy = ((buffer[0] & 0x01) != 0);
2699: no_windows = ((buffer[0] & 0x02) != 0);
2700: standard_env = ((buffer[0] & 0x04) != 0);
2701: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
2702: limit_max_memory = ((buffer[0] & 0x10) != 0);
2703: if((buffer[0] & 0x20) != 0) {
2704: get_sio_port_numbers();
2705: }
2706: if((buffer[0] & 0x40) != 0) {
2707: UMB_TOP = EMS_TOP + EMS_SIZE;
2708: support_ems = true;
2709: }
2710: #ifdef SUPPORT_XMS
2711: if((buffer[0] & 0x80) != 0) {
2712: support_xms = true;
2713: }
2714: #endif
2715: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
2716: buf_width = buffer[1] | (buffer[2] << 8);
2717: buf_height = buffer[3] | (buffer[4] << 8);
2718: }
2719: if(buffer[5] != 0) {
2720: dos_major_version = buffer[5];
2721: dos_minor_version = buffer[6];
2722: }
2723: if(buffer[7] != 0) {
2724: win_major_version = buffer[7];
2725: win_minor_version = buffer[8];
2726: }
2727: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
2728: SetConsoleCP(code_page);
2729: SetConsoleOutputCP(code_page);
2730: }
2731: int name_len = buffer[11];
2732: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
2733:
2734: // restore command file name
2735: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
2736: fread(dummy_argv_1, name_len, 1, fp);
2737:
2738: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
2739: // if original command file exists, create a temporary file name
2740: if(GetTempFileNameA(".", "DOS", 0, dummy_argv_1) != 0) {
2741: // create a temporary command file in the current director
2742: DeleteFileA(dummy_argv_1);
2743: } else {
2744: // create a temporary command file in the temporary folder
2745: GetTempPathA(MAX_PATH, path);
2746: if(GetTempFileNameA(path, "DOS", 0, dummy_argv_1) != 0) {
2747: DeleteFileA(dummy_argv_1);
2748: } else {
2749: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
2750: }
2751: }
2752: // check the command file type
2753: fread(buffer, 2, 1, fp);
2754: fseek(fp, -2, SEEK_CUR);
2755: if(memcmp(buffer, "MZ", 2) != 0) {
2756: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
2757: } else {
2758: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
2759: }
2760: }
2761:
2762: // restore command file
2763: FILE* fo = fopen(dummy_argv_1, "wb");
2764: for(int i = 0; i < file_len; i++) {
2765: fputc(fgetc(fp), fo);
2766: }
2767: fclose(fo);
2768:
2769: GetFullPathNameA(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
2770: temp_file_created = true;
2771: SetFileAttributesA(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
2772:
2773: // adjust argc/argv
2774: for(int i = 1; i < argc && (i + 1) < 256; i++) {
2775: dummy_argv[i + 1] = argv[i];
2776: }
2777: argc++;
2778: argv = dummy_argv;
2779: }
2780: fclose(fp);
2781: }
2782: for(int i = 1; i < argc; i++) {
2783: if(_strnicmp(argv[i], "-b", 2) == 0) {
2784: stay_busy = true;
2785: arg_offset++;
2786: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
2787: if(argv[i][2] != '\0') {
2788: strcpy(new_exec_file, &argv[i][2]);
2789: } else {
2790: strcpy(new_exec_file, "new_exec_file.exe");
2791: }
2792: convert_cmd_file = true;
2793: arg_offset++;
2794: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
2795: if(IS_NUMERIC(argv[i][2])) {
2796: code_page = atoi(&argv[i][2]);
2797: } else {
2798: code_page = GetConsoleCP();
2799: }
2800: arg_offset++;
2801: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
2802: no_windows = true;
2803: arg_offset++;
2804: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
2805: standard_env = 1;
2806: arg_offset++;
2807: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
2808: ignore_illegal_insn = true;
2809: arg_offset++;
2810: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
2811: limit_max_memory = true;
2812: arg_offset++;
2813: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
2814: int result = sscanf(argv[i] + 2, "%d,%d", &buf_height, &buf_width);
2815: if(result == 1) {
2816: buf_width = 0;
2817: } else if(result != 2) {
2818: buf_width = buf_height = 0;
2819: }
2820: if(buf_width <= 0 || buf_width > 0x7fff) {
2821: buf_width = 80;
2822: }
2823: if(buf_height <= 0 || buf_height > 0x7fff) {
2824: buf_height = 25;
2825: }
2826: arg_offset++;
2827: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
2828: if(IS_NUMERIC(argv[i][2])) {
2829: char *p0 = &argv[i][2], *p1, *p2, *p3;
2830: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
2831: sio_port_number[1] = atoi(p1 + 1);
2832: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
2833: sio_port_number[2] = atoi(p2 + 1);
2834: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
2835: sio_port_number[3] = atoi(p3 + 1);
2836: }
2837: }
2838: }
2839: sio_port_number[0] = atoi(p0);
2840: }
2841: if(sio_port_number[0] == 0 || sio_port_number[1] == 0 || sio_port_number[2] == 0 || sio_port_number[3] == 0) {
2842: get_sio_port_numbers();
2843: }
2844: arg_offset++;
2845: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
2846: 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]))) {
2847: dos_major_version = argv[i][2] - '0';
2848: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2849: }
2850: arg_offset++;
2851: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
2852: 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]))) {
2853: win_major_version = argv[i][2] - '0';
2854: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2855: }
2856: arg_offset++;
2857: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
2858: UMB_TOP = EMS_TOP + EMS_SIZE;
2859: support_ems = true;
2860: #ifdef SUPPORT_XMS
2861: support_xms = true;
2862: #endif
2863: arg_offset++;
2864: } else {
2865: break;
2866: }
2867: }
2868: if(argc < 2 + arg_offset) {
2869: #ifdef _WIN64
2870: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
2871: #else
2872: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
2873: #endif
2874: fprintf(stderr,
2875: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
2876: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
2877: "\n"
2878: "\t-b\tstay busy during keyboard polling\n"
2879: #ifdef _WIN64
2880: "\t-c\tconvert command file to 64bit execution file\n"
2881: #else
2882: "\t-c\tconvert command file to 32bit execution file\n"
2883: #endif
2884: "\t-p\trecord current code page when convert command file\n"
2885: "\t-d\tpretend running under straight DOS, not Windows\n"
2886: "\t-e\tuse a reduced environment block\n"
2887: "\t-i\tignore invalid instructions\n"
2888: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
2889: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
2890: "\t-s\tenable serial I/O and set host's COM port numbers\n"
2891: "\t-v\tset the DOS version\n"
2892: "\t-w\tset the Windows version\n"
2893: #if defined(SUPPORT_VCPI)
2894: "\t-x\tenable LIM EMS, VCPI, and XMS\n"
2895: #elif defined(SUPPORT_XMS)
2896: "\t-x\tenable LIM EMS and XMS\n"
2897: #else
2898: "\t-x\tenable LIM EMS\n"
2899: #endif
2900: );
2901:
2902: if(!is_started_from_command_prompt()) {
2903: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
2904: while(!_kbhit()) {
2905: Sleep(10);
2906: }
2907: }
2908: #ifdef _DEBUG
2909: _CrtDumpMemoryLeaks();
2910: #endif
2911: return(EXIT_FAILURE);
2912: }
2913: if(convert_cmd_file) {
2914: retval = EXIT_FAILURE;
2915: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
2916: FILE *fp = NULL, *fs = NULL, *fo = NULL;
2917: int len = strlen(argv[arg_offset + 1]), data;
2918:
2919: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
2920: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
2921: } else if((fp = fopen(full, "rb")) == NULL) {
2922: fprintf(stderr, "Can't open '%s'\n", name);
2923: } else {
2924: long offset = get_section_in_exec_file(fp, ".msdos");
2925: if(offset != 0) {
2926: UINT8 buffer[14];
2927: fseek(fp, offset, SEEK_SET);
2928: fread(buffer, sizeof(buffer), 1, fp);
2929: memset(path, 0, sizeof(path));
2930: fread(path, buffer[9], 1, fp);
2931: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
2932: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
2933: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
2934: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
2935: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
2936: } else {
2937: // read pe header of msdos.exe
2938: UINT8 header[0x400];
2939: fseek(fp, 0, SEEK_SET);
2940: fread(header, sizeof(header), 1, fp);
2941:
2942: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2943: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2944: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2945: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2946: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2947: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
2948: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2949:
2950: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
2951: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
2952: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
2953: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
2954: if(dwExtraLastSectionBytes != 0) {
2955: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
2956: dwLastSectionSize += dwRemain;
2957: }
2958: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
2959:
2960: // store msdos.exe
2961: fseek(fp, 0, SEEK_SET);
2962: for(int i = 0; i < dwEndOfFile; i++) {
2963: if((data = fgetc(fp)) != EOF) {
2964: fputc(data, fo);
2965: } else {
2966: // we should not reach here :-(
2967: fputc(0, fo);
2968: }
2969: }
2970:
2971: // store options
2972: UINT8 flags = 0;
2973: if(stay_busy) {
2974: flags |= 0x01;
2975: }
2976: if(no_windows) {
2977: flags |= 0x02;
2978: }
2979: if(standard_env) {
2980: flags |= 0x04;
2981: }
2982: if(ignore_illegal_insn) {
2983: flags |= 0x08;
2984: }
2985: if(limit_max_memory) {
2986: flags |= 0x10;
2987: }
2988: if(sio_port_number[0] != 0 || sio_port_number[1] != 0 || sio_port_number[2] != 0 || sio_port_number[3] != 0) {
2989: flags |= 0x20;
2990: }
2991: if(support_ems) {
2992: flags |= 0x40;
2993: }
2994: #ifdef SUPPORT_XMS
2995: if(support_xms) {
2996: flags |= 0x80;
2997: }
2998: #endif
2999:
3000: fputc(flags, fo);
3001: fputc((buf_width >> 0) & 0xff, fo);
3002: fputc((buf_width >> 8) & 0xff, fo);
3003: fputc((buf_height >> 0) & 0xff, fo);
3004: fputc((buf_height >> 8) & 0xff, fo);
3005: fputc(dos_major_version, fo);
3006: fputc(dos_minor_version, fo);
3007: fputc(win_major_version, fo);
3008: fputc(win_minor_version, fo);
3009: fputc((code_page >> 0) & 0xff, fo);
3010: fputc((code_page >> 8) & 0xff, fo);
3011:
3012: // store command file info
3013: GetFullPathNameA(argv[arg_offset + 1], MAX_PATH, full, &name);
3014: int name_len = strlen(name);
3015: fseek(fs, 0, SEEK_END);
3016: long file_size = ftell(fs);
3017:
3018: fputc(name_len, fo);
3019: fputc((file_size >> 0) & 0xff, fo);
3020: fputc((file_size >> 8) & 0xff, fo);
3021: fputc((file_size >> 16) & 0xff, fo);
3022: fputc((file_size >> 24) & 0xff, fo);
3023: fwrite(name, name_len, 1, fo);
3024:
3025: // store command file
3026: fseek(fs, 0, SEEK_SET);
3027: for(int i = 0; i < file_size; i++) {
3028: if((data = fgetc(fs)) != EOF) {
3029: fputc(data, fo);
3030: } else {
3031: // we should not reach here :-(
3032: fputc(0, fo);
3033: }
3034: }
3035:
3036: // store padding data and update pe header
3037: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
3038: coffHeader->NumberOfSections++;
3039: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
3040: memcpy(newSectionHeader->Name, ".msdos", 6);
3041: newSectionHeader->VirtualAddress = dwVirtualAddress;
3042: newSectionHeader->PointerToRawData = dwEndOfFile;
3043: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
3044: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
3045: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
3046: if(dwExtraRawBytes != 0) {
3047: static const char padding[] = "PADDINGXXPADDING";
3048: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
3049: for(int i = 0; i < dwRemain; i++) {
3050: if(i < 2) {
3051: fputc(padding[i & 15], fo);
3052: } else {
3053: fputc(padding[(i - 2) & 15], fo);
3054: }
3055: }
3056: newSectionHeader->SizeOfRawData += dwRemain;
3057: }
3058: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
3059:
3060: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
3061: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
3062: if(dwExtraNewSectionBytes != 0) {
3063: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
3064: dwNewSectionSize += dwRemain;
3065: }
3066: optionalHeader->SizeOfImage += dwNewSectionSize;
3067:
3068: fseek(fo, 0, SEEK_SET);
3069: fwrite(header, sizeof(header), 1, fo);
3070:
3071: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
3072: retval = EXIT_SUCCESS;
3073: }
3074: }
3075: if(fp != NULL) {
3076: fclose(fp);
3077: }
3078: if(fs != NULL) {
3079: fclose(fs);
3080: }
3081: if(fo != NULL) {
3082: fclose(fo);
3083: }
3084: }
3085: #ifdef _DEBUG
3086: _CrtDumpMemoryLeaks();
3087: #endif
3088: return(retval);
3089: }
3090:
3091: is_winxp_or_later = is_greater_windows_version(5, 1, 0, 0);
3092: is_xp_64_or_later = is_greater_windows_version(5, 2, 0, 0);
3093: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
3094:
3095: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
3096: CONSOLE_SCREEN_BUFFER_INFO csbi;
3097: CONSOLE_CURSOR_INFO ci;
3098: UINT input_cp = GetConsoleCP();
3099: UINT output_cp = GetConsoleOutputCP();
3100: int multibyte_cp = _getmbcp();
3101:
3102: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
3103: GetConsoleCursorInfo(hStdout, &ci);
3104: ci_old = ci_new = ci;
3105: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
3106: get_console_font_success = get_console_font_size(&font_width, &font_height);
3107:
3108: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
3109: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
3110: SCR_BUF(y,x).Char.AsciiChar = ' ';
3111: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
3112: }
3113: }
3114: if(get_console_info_success) {
3115: scr_width = csbi.dwSize.X;
3116: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3117:
3118: // v-text shadow buffer size must be lesser than 0x7fd0
3119: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
3120: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
3121: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
3122: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
3123: if(scr_width * scr_height * 2 > 0x7fd0) {
3124: scr_width = 80;
3125: scr_height = 25;
3126: }
3127: screen_size_changed = true;
3128: }
3129: } else {
3130: // for a proof (not a console)
3131: scr_width = 80;
3132: scr_height = 25;
3133: }
3134: scr_buf_size.X = scr_width;
3135: scr_buf_size.Y = scr_height;
3136: scr_buf_pos.X = scr_buf_pos.Y = 0;
3137: scr_top = csbi.srWindow.Top;
3138: cursor_moved = false;
3139: cursor_moved_by_crtc = false;
3140:
3141: SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
3142:
3143: #ifdef USE_SERVICE_THREAD
3144: InitializeCriticalSection(&input_crit_sect);
3145: InitializeCriticalSection(&key_buf_crit_sect);
3146: InitializeCriticalSection(&putch_crit_sect);
3147: main_thread_id = GetCurrentThreadId();
3148: #endif
3149:
3150: key_buf_char = new FIFO(256);
3151: key_buf_scan = new FIFO(256);
3152: key_buf_data = new FIFO(256);
3153:
3154: hardware_init();
3155:
3156: #ifdef USE_DEBUGGER
3157: debugger_init();
3158: #endif
3159:
3160: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
3161: retval = EXIT_FAILURE;
3162: } else {
3163: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
3164: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
3165: #endif
3166: SetConsoleCtrlHandler(ctrl_handler, TRUE);
3167:
3168: if(screen_size_changed) {
3169: change_console_size(scr_width, scr_height);
3170: }
3171: TIMECAPS caps;
3172: timeGetDevCaps(&caps, sizeof(TIMECAPS));
3173: timeBeginPeriod(caps.wPeriodMin);
3174: #ifdef USE_VRAM_THREAD
3175: InitializeCriticalSection(&vram_crit_sect);
3176: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
3177: #endif
3178: #ifdef USE_DEBUGGER
3179: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL));
3180: // wait until telnet client starts and connects to me
3181: if(_access(debugger_get_ttermpro_path(), 0) == 0 ||
3182: _access(debugger_get_ttermpro_x86_path(), 0) == 0 ||
3183: _access(debugger_get_putty_path(), 0) == 0 ||
3184: _access(debugger_get_putty_x86_path(), 0) == 0 ||
3185: _access(debugger_get_telnet_path(), 0) == 0) {
3186: for(int i = 0; i < 100 && cli_socket == 0; i++) {
3187: Sleep(100);
3188: }
3189: }
3190: #endif
3191: hardware_run();
3192: #ifdef USE_VRAM_THREAD
3193: vram_flush();
3194: DeleteCriticalSection(&vram_crit_sect);
3195: #endif
3196: timeEndPeriod(caps.wPeriodMin);
3197:
3198: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
3199: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
3200:
3201: // restore console settings
3202: _setmbcp(multibyte_cp);
3203: SetConsoleCP(input_cp);
3204: SetConsoleOutputCP(multibyte_cp);
3205:
3206: if(get_console_info_success) {
3207: if(restore_console_on_exit) {
3208: // window can't be bigger than buffer,
3209: // buffer can't be smaller than window,
3210: // so make a tiny window,
3211: // set the required buffer,
3212: // then set the required window
3213: CONSOLE_SCREEN_BUFFER_INFO cur_csbi;
3214: SMALL_RECT rect;
3215: GetConsoleScreenBufferInfo(hStdout, &cur_csbi);
3216: int min_width = min(cur_csbi.srWindow.Right - cur_csbi.srWindow.Left + 1, csbi.srWindow.Right - csbi.srWindow.Left + 1);
3217: int min_height = min(cur_csbi.srWindow.Bottom - cur_csbi.srWindow.Top + 1, csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
3218:
3219: SET_RECT(rect, 0, cur_csbi.srWindow.Top, min_width - 1, cur_csbi.srWindow.Top + min_height - 1);
3220: SetConsoleWindowInfo(hStdout, TRUE, &rect);
3221: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
3222: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
3223: if(!SetConsoleWindowInfo(hStdout, TRUE, &rect)) {
3224: SetWindowPos(get_console_window_handle(), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
3225: SetConsoleWindowInfo(hStdout, TRUE, &rect);
3226: }
3227: }
3228: }
3229: if(get_console_font_success) {
3230: set_console_font_size(font_width, font_height);
3231: }
3232: if(get_console_info_success) {
3233: if(restore_console_on_exit) {
3234: SMALL_RECT rect;
3235: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
3236: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
3237: if(!SetConsoleWindowInfo(hStdout, TRUE, &rect)) {
3238: SetWindowPos(get_console_window_handle(), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
3239: SetConsoleWindowInfo(hStdout, TRUE, &rect);
3240: }
3241: }
3242: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3243: SetConsoleCursorInfo(hStdout, &ci);
3244: }
3245: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) {
3246: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS);
3247: } else {
3248: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
3249: }
3250:
3251: msdos_finish();
3252:
3253: SetConsoleCtrlHandler(ctrl_handler, FALSE);
3254: }
3255: if(temp_file_created) {
3256: DeleteFileA(temp_file_path);
3257: temp_file_created = false;
3258: }
3259: hardware_finish();
3260:
3261: if(key_buf_char != NULL) {
3262: key_buf_char->release();
3263: delete key_buf_char;
3264: key_buf_char = NULL;
3265: }
3266: if(key_buf_scan != NULL) {
3267: key_buf_scan->release();
3268: delete key_buf_scan;
3269: key_buf_scan = NULL;
3270: }
3271: if(key_buf_data != NULL) {
3272: key_buf_data->release();
3273: delete key_buf_data;
3274: key_buf_data = NULL;
3275: }
3276: #ifdef USE_SERVICE_THREAD
3277: DeleteCriticalSection(&input_crit_sect);
3278: DeleteCriticalSection(&key_buf_crit_sect);
3279: DeleteCriticalSection(&putch_crit_sect);
3280: #endif
3281: #ifdef _DEBUG
3282: _CrtDumpMemoryLeaks();
3283: #endif
3284: return(retval);
3285: }
3286:
3287: /* ----------------------------------------------------------------------------
3288: console
3289: ---------------------------------------------------------------------------- */
3290:
3291: void change_console_size(int width, int height)
3292: {
3293: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
3294: CONSOLE_SCREEN_BUFFER_INFO csbi;
3295: SMALL_RECT rect;
3296: COORD co;
3297:
3298: GetConsoleScreenBufferInfo(hStdout, &csbi);
3299: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
3300: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
3301: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
3302: SET_RECT(rect, 0, 0, width - 1, height - 1);
3303: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3304: } else if(csbi.dwCursorPosition.Y > height - 1) {
3305: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
3306: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3307: SET_RECT(rect, 0, 0, width - 1, height - 1);
3308: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3309: }
3310: }
3311: if(csbi.dwCursorPosition.Y > height - 1) {
3312: co.X = csbi.dwCursorPosition.X;
3313: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
3314: SetConsoleCursorPosition(hStdout, co);
3315: cursor_moved = true;
3316: cursor_moved_by_crtc = false;
3317: }
3318:
3319: // window can't be bigger than buffer,
3320: // buffer can't be smaller than window,
3321: // so make a tiny window,
3322: // set the required buffer,
3323: // then set the required window
3324: int min_width = min(csbi.srWindow.Right - csbi.srWindow.Left + 1, width);
3325: int min_height = min(csbi.srWindow.Bottom - csbi.srWindow.Top + 1, height);
3326:
3327: SET_RECT(rect, 0, csbi.srWindow.Top, min_width - 1, csbi.srWindow.Top + min_height - 1);
3328: SetConsoleWindowInfo(hStdout, TRUE, &rect);
3329: co.X = width;
3330: co.Y = height;
3331: SetConsoleScreenBufferSize(hStdout, co);
3332: SET_RECT(rect, 0, 0, width - 1, height - 1);
3333: if(!SetConsoleWindowInfo(hStdout, TRUE, &rect)) {
3334: SetWindowPos(get_console_window_handle(), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
3335: SetConsoleWindowInfo(hStdout, TRUE, &rect);
3336: }
3337:
3338: scr_width = scr_buf_size.X = width;
3339: scr_height = scr_buf_size.Y = height;
3340: scr_top = 0;
3341:
3342: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
3343:
3344: int regen = min(scr_width * scr_height * 2, 0x8000);
3345: text_vram_end_address = text_vram_top_address + regen;
3346: shadow_buffer_end_address = shadow_buffer_top_address + regen;
3347:
3348: if(regen > 0x4000) {
3349: regen = 0x8000;
3350: vram_pages = 1;
3351: } else if(regen > 0x2000) {
3352: regen = 0x4000;
3353: vram_pages = 2;
3354: } else if(regen > 0x1000) {
3355: regen = 0x2000;
3356: vram_pages = 4;
3357: } else {
3358: regen = 0x1000;
3359: vram_pages = 8;
3360: }
3361: *(UINT16 *)(mem + 0x44a) = scr_width;
3362: *(UINT16 *)(mem + 0x44c) = regen;
3363: *(UINT8 *)(mem + 0x484) = scr_height - 1;
3364:
3365: mouse.min_position.x = 0;
3366: mouse.min_position.y = 0;
3367: mouse.max_position.x = 8 * (scr_width - 1);
3368: mouse.max_position.y = 8 * (scr_height - 1);
3369:
3370: restore_console_on_exit = true;
3371: }
3372:
3373: void clear_scr_buffer(WORD attr)
3374: {
3375: for(int y = 0; y < scr_height; y++) {
3376: for(int x = 0; x < scr_width; x++) {
3377: SCR_BUF(y,x).Char.AsciiChar = ' ';
3378: SCR_BUF(y,x).Attributes = attr;
3379: }
3380: }
3381: }
3382:
3383: bool update_console_input()
3384: {
3385: #ifdef USE_SERVICE_THREAD
3386: EnterCriticalSection(&input_crit_sect);
3387: #endif
3388: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
3389: DWORD dwNumberOfEvents = 0;
3390: DWORD dwRead;
3391: INPUT_RECORD ir[16];
3392: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
3393: bool result = false;
3394:
3395: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
3396: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
3397: for(int i = 0; i < dwRead; i++) {
3398: if(ir[i].EventType & MOUSE_EVENT) {
3399: if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) {
3400: if(mouse.hidden == 0 || (mouse.call_addr_ps2.dw && mouse.enabled_ps2)) {
3401: // NOTE: if restore_console_on_exit, console is not scrolled
3402: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
3403: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
3404: }
3405: // FIXME: character size is always 8x8 ???
3406: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
3407: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
3408:
3409: if(mouse.position.x != x || mouse.position.y != y) {
3410: mouse.position.x = x;
3411: mouse.position.y = y;
3412: mouse.status |= 1;
3413: mouse.status_alt |= 1;
3414: }
3415: }
3416: } else if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
3417: for(int j = 0; j < MAX_MOUSE_BUTTONS; j++) {
3418: static const DWORD bits[] = {
3419: FROM_LEFT_1ST_BUTTON_PRESSED, // left
3420: RIGHTMOST_BUTTON_PRESSED, // right
3421: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
3422: };
3423: bool prev_status = mouse.buttons[j].status;
3424: mouse.buttons[j].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[j]) != 0);
3425:
3426: if(!prev_status && mouse.buttons[j].status) {
3427: mouse.buttons[j].pressed_times++;
3428: mouse.buttons[j].pressed_position.x = mouse.position.x;
3429: mouse.buttons[j].pressed_position.y = mouse.position.x;
3430: if(j < 2) {
3431: mouse.status_alt |= 2 << (j * 2);
3432: }
3433: mouse.status |= 2 << (j * 2);
3434: } else if(prev_status && !mouse.buttons[j].status) {
3435: mouse.buttons[j].released_times++;
3436: mouse.buttons[j].released_position.x = mouse.position.x;
3437: mouse.buttons[j].released_position.y = mouse.position.x;
3438: if(j < 2) {
3439: mouse.status_alt |= 4 << (j * 2);
3440: }
3441: mouse.status |= 4 << (j * 2);
3442: }
3443: }
3444: }
3445: } else if(ir[i].EventType & KEY_EVENT) {
3446: // update keyboard flags in bios data area
3447: if(ir[i].Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) {
3448: mem[0x417] |= 0x40;
3449: } else {
3450: mem[0x417] &= ~0x40;
3451: }
3452: if(ir[i].Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) {
3453: mem[0x417] |= 0x20;
3454: } else {
3455: mem[0x417] &= ~0x20;
3456: }
3457: if(ir[i].Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) {
3458: mem[0x417] |= 0x10;
3459: } else {
3460: mem[0x417] &= ~0x10;
3461: }
3462: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3463: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3464: mouse.status_alt |= 0x80;
3465: }
3466: mem[0x417] |= 0x08;
3467: } else {
3468: mem[0x417] &= ~0x08;
3469: }
3470: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3471: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3472: mouse.status_alt |= 0x40;
3473: }
3474: mem[0x417] |= 0x04;
3475: } else {
3476: mem[0x417] &= ~0x04;
3477: }
3478: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3479: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3480: mouse.status_alt |= 0x20;
3481: }
3482: if(!(mem[0x417] & 0x03)) {
3483: mem[0x417] |= 0x02; // left shift
3484: }
3485: } else {
3486: mem[0x417] &= ~0x03;
3487: }
3488: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) {
3489: mem[0x418] |= 0x02;
3490: } else {
3491: mem[0x418] &= ~0x02;
3492: }
3493: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
3494: mem[0x418] |= 0x01;
3495: } else {
3496: mem[0x418] &= ~0x01;
3497: }
3498:
3499: // set scan code of last pressed/release key to kbd_data (in-port 60h)
3500: // kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
3501: // kbd_status |= 1;
3502: UINT8 tmp_data = ir[i].Event.KeyEvent.wVirtualScanCode;
3503:
3504: // update dos key buffer
3505: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
3506: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
3507: UINT8 scn_old = scn;
3508:
3509: if(ir[i].Event.KeyEvent.bKeyDown) {
3510: // make
3511: tmp_data &= 0x7f;
3512:
3513: if(chr == 0x00) {
3514: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3515: if(scn >= 0x3b && scn <= 0x44) {
3516: scn += 0x68 - 0x3b; // F1 to F10
3517: } else if(scn == 0x57 || scn == 0x58) {
3518: scn += 0x8b - 0x57; // F11 & F12
3519: } else if(scn >= 0x47 && scn <= 0x53) {
3520: scn += 0x97 - 0x47; // edit/arrow clusters
3521: } else if(scn == 0x35) {
3522: scn = 0xa4; // keypad /
3523: }
3524: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3525: if(scn == 0x07) {
3526: chr = 0x1e; // Ctrl+^
3527: } else if(scn == 0x0c) {
3528: chr = 0x1f; // Ctrl+_
3529: } else if(scn >= 0x35 && scn <= 0x58) {
3530: static const UINT8 ctrl_map[] = {
3531: 0x95, // keypad /
3532: 0,
3533: 0x96, // keypad *
3534: 0, 0, 0,
3535: 0x5e, // F1
3536: 0x5f, // F2
3537: 0x60, // F3
3538: 0x61, // F4
3539: 0x62, // F5
3540: 0x63, // F6
3541: 0x64, // F7
3542: 0x65, // F8
3543: 0x66, // F9
3544: 0x67, // F10
3545: 0,
3546: 0,
3547: 0x77, // Home
3548: 0x8d, // Up
3549: 0x84, // PgUp
3550: 0x8e, // keypad -
3551: 0x73, // Left
3552: 0x8f, // keypad center
3553: 0x74, // Right
3554: 0x90, // keyapd +
3555: 0x75, // End
3556: 0x91, // Down
3557: 0x76, // PgDn
3558: 0x92, // Insert
3559: 0x93, // Delete
3560: 0, 0, 0,
3561: 0x89, // F11
3562: 0x8a, // F12
3563: };
3564: scn = ctrl_map[scn - 0x35];
3565: }
3566: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3567: if(scn >= 0x3b && scn <= 0x44) {
3568: scn += 0x54 - 0x3b; // F1 to F10
3569: } else if(scn == 0x57 || scn == 0x58) {
3570: scn += 0x87 - 0x57; // F11 & F12
3571: }
3572: } else if(scn == 0x57 || scn == 0x58) {
3573: scn += 0x85 - 0x57;
3574: }
3575: // ignore shift, ctrl, alt, win and menu keys
3576: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && !(scn >= 0x5b && scn <= 0x5d && scn == scn_old)) {
3577: if(key_buf_char != NULL && key_buf_scan != NULL) {
3578: #ifdef USE_SERVICE_THREAD
3579: EnterCriticalSection(&key_buf_crit_sect);
3580: #endif
3581: if(chr == 0) {
3582: pcbios_set_key_buffer(0x00, ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
3583: }
3584: pcbios_set_key_buffer(chr, scn);
3585: #ifdef USE_SERVICE_THREAD
3586: LeaveCriticalSection(&key_buf_crit_sect);
3587: #endif
3588: }
3589: }
3590: } else {
3591: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3592: chr = 0;
3593: if(scn >= 0x02 && scn <= 0x0e) {
3594: scn += 0x78 - 0x02; // 1 to 0 - =
3595: }
3596: }
3597: if(key_buf_char != NULL && key_buf_scan != NULL) {
3598: #ifdef USE_SERVICE_THREAD
3599: EnterCriticalSection(&key_buf_crit_sect);
3600: #endif
3601: pcbios_set_key_buffer(chr, scn);
3602: #ifdef USE_SERVICE_THREAD
3603: LeaveCriticalSection(&key_buf_crit_sect);
3604: #endif
3605: }
3606: }
3607: } else {
3608: if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) {
3609: // ctrl-break, ctrl-c
3610: if(scn == 0x46) {
3611: if(key_buf_char != NULL && key_buf_scan != NULL) {
3612: #ifdef USE_SERVICE_THREAD
3613: EnterCriticalSection(&key_buf_crit_sect);
3614: #endif
3615: pcbios_set_key_buffer(0x00, 0x00);
3616: #ifdef USE_SERVICE_THREAD
3617: LeaveCriticalSection(&key_buf_crit_sect);
3618: #endif
3619: }
3620: ctrl_break_pressed = true;
3621: mem[0x471] = 0x80;
3622: raise_int_1bh = true;
3623: } else {
3624: if(key_buf_char != NULL && key_buf_scan != NULL) {
3625: #ifdef USE_SERVICE_THREAD
3626: EnterCriticalSection(&key_buf_crit_sect);
3627: #endif
3628: pcbios_set_key_buffer(chr, scn);
3629: #ifdef USE_SERVICE_THREAD
3630: LeaveCriticalSection(&key_buf_crit_sect);
3631: #endif
3632: }
3633: ctrl_c_pressed = (scn == 0x2e);
3634: }
3635: }
3636: // break
3637: tmp_data |= 0x80;
3638: }
3639: if(!(kbd_status & 1)) {
3640: kbd_data = tmp_data;
3641: kbd_status |= 1;
3642: } else {
3643: if(key_buf_data != NULL) {
3644: #ifdef USE_SERVICE_THREAD
3645: EnterCriticalSection(&key_buf_crit_sect);
3646: #endif
3647: key_buf_data->write(tmp_data);
3648: #ifdef USE_SERVICE_THREAD
3649: LeaveCriticalSection(&key_buf_crit_sect);
3650: #endif
3651: }
3652: }
3653: result = key_changed = true;
3654: // IME may be on and it may causes screen scroll up and cursor position change
3655: cursor_moved = true;
3656: }
3657: }
3658: }
3659: }
3660: #ifdef USE_SERVICE_THREAD
3661: LeaveCriticalSection(&input_crit_sect);
3662: #endif
3663: return(result);
3664: }
3665:
3666: bool update_key_buffer()
3667: {
3668: if(update_console_input()) {
3669: return(true);
3670: }
3671: if(key_buf_char != NULL && key_buf_scan != NULL) {
3672: #ifdef USE_SERVICE_THREAD
3673: EnterCriticalSection(&key_buf_crit_sect);
3674: #endif
3675: bool empty = pcbios_is_key_buffer_empty();
3676: #ifdef USE_SERVICE_THREAD
3677: LeaveCriticalSection(&key_buf_crit_sect);
3678: #endif
3679: if(!empty) return(true);
3680: }
3681: return(false);
3682: }
3683:
3684: /* ----------------------------------------------------------------------------
3685: MS-DOS virtual machine
3686: ---------------------------------------------------------------------------- */
3687:
3688: static const struct {
3689: char *name;
3690: DWORD lcid;
3691: char *std;
3692: char *dlt;
3693: } tz_table[] = {
3694: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
3695: // 0 GMT Greenwich Mean Time GMT0
3696: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
3697: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
3698: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
3699: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
3700: // 2 FST FDT Fernando De Noronha Std FST2FDT
3701: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3702: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3703: // 3 BST Brazil Standard Time BST3
3704: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
3705: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
3706: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
3707: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
3708: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
3709: // 3 GST Greenland Standard Time GST3
3710: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
3711: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
3712: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
3713: // 4 AST ADT Atlantic Standard Time AST4ADT
3714: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
3715: // 4 WST WDT Western Standard (Brazil) WST4WDT
3716: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
3717: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
3718: // 5 EST EDT Eastern Standard Time EST5EDT
3719: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
3720: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
3721: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
3722: // 5 CST CDT Chile Standard Time CST5CDT
3723: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
3724: // 5 AST ADT Acre Standard Time AST5ADT
3725: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
3726: // 5 CST CDT Cuba Standard Time CST5CDT
3727: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
3728: // 6 CST CDT Central Standard Time CST6CDT
3729: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
3730: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
3731: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
3732: // 6 EST EDT Easter Island Standard EST6EDT
3733: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
3734: // 7 MST MDT Mountain Standard Time MST7MDT
3735: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
3736: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
3737: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
3738: // 8 PST PDT Pacific Standard Time PST8PDT
3739: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
3740: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
3741: // 9 AKS AKD Alaska Standard Time AKS9AKD
3742: // 9 YST YDT Yukon Standard Time YST9YST
3743: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
3744: // 10 HST HDT Hawaii Standard Time HST10HDT
3745: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
3746: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
3747: // 11 SST Samoa Standard Time SST11
3748: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
3749: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
3750: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
3751: // -10 GST Guam Standard Time GST-10
3752: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
3753: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
3754: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
3755: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
3756: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
3757: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
3758: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
3759: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
3760: // -9 JST Japan Standard Time JST-9
3761: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
3762: // -9 KST KDT Korean Standard Time KST-9KDT
3763: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
3764: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
3765: // -8 HKT Hong Kong Time HKT-8
3766: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
3767: // -8 CCT China Coast Time CCT-8
3768: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
3769: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
3770: // -8 SST Singapore Standard Time SST-8
3771: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
3772: // -8 WAS WAD Western Australian Standard WAS-8WAD
3773: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
3774: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
3775: // -7:30 JT Java Standard Time JST-7:30
3776: // -7 NST North Sumatra Time NST-7
3777: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
3778: // -5:30 IST Indian Standard Time IST-5:30
3779: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
3780: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
3781: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
3782: // -3 MSK MSD Moscow Winter Time MSK-3MSD
3783: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
3784: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
3785: // -2 EET Eastern Europe Time EET-2
3786: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
3787: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
3788: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
3789: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
3790: // -2 IST IDT Israel Standard Time IST-2IDT
3791: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
3792: // -1 MEZ MES Middle European Time MEZ-1MES
3793: // -1 SWT SST Swedish Winter Time SWT-1SST
3794: // -1 FWT FST French Winter Time FWT-1FST
3795: // -1 CET CES Central European Time CET-1CES
3796: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
3797: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
3798: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
3799: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
3800: // -1 WAT West African Time WAT-1
3801: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
3802: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
3803: // 0 UTC Universal Coordinated Time UTC0
3804: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
3805: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
3806: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
3807: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
3808: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
3809: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
3810: };
3811:
3812: // FIXME: consider to build on non-Japanese environment :-(
3813: // message_japanese string must be in shift-jis
3814:
3815: static const struct {
3816: UINT16 code;
3817: char *message_english;
3818: char *message_japanese;
3819: } standard_error_table[] = {
3820: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3821: {0x02, "File not found", "�t�@�C����������܂���."},
3822: {0x03, "Path not found", "�p�X��������܂���."},
3823: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3824: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3825: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3826: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3827: {0x08, "Insufficient memory", "������������܂���."},
3828: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3829: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3830: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3831: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3832: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3833: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3834: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3835: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3836: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3837: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3838: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3839: {0x15, "Not ready", "�������ł��Ă��܂���."},
3840: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3841: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3842: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3843: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3844: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3845: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3846: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3847: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3848: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3849: {0x1F, "General failure", "�G���[�ł�."},
3850: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3851: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3852: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3853: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3854: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3855: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3856: {0x26, "Out of input", "���͂��I���܂���."},
3857: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3858: /*
3859: {0x32, "Network request not supported", NULL},
3860: {0x33, "Remote computer not listening", NULL},
3861: {0x34, "Duplicate name on network", NULL},
3862: {0x35, "Network name not found", NULL},
3863: {0x36, "Network busy", NULL},
3864: {0x37, "Network device no longer exists", NULL},
3865: {0x38, "Network BIOS command limit exceeded", NULL},
3866: {0x39, "Network adapter hardware error", NULL},
3867: {0x3A, "Incorrect response from network", NULL},
3868: {0x3B, "Unexpected network error", NULL},
3869: {0x3C, "Incompatible remote adapter", NULL},
3870: {0x3D, "Print queue full", NULL},
3871: {0x3E, "Queue not full", NULL},
3872: {0x3F, "Not enough space to print file", NULL},
3873: {0x40, "Network name was deleted", NULL},
3874: {0x41, "Network: Access denied", NULL},
3875: {0x42, "Network device type incorrect", NULL},
3876: {0x43, "Network name not found", NULL},
3877: {0x44, "Network name limit exceeded", NULL},
3878: {0x45, "Network BIOS session limit exceeded", NULL},
3879: {0x46, "Temporarily paused", NULL},
3880: {0x47, "Network request not accepted", NULL},
3881: {0x48, "Network print/disk redirection paused", NULL},
3882: {0x49, "Network software not installed", NULL},
3883: {0x4A, "Unexpected adapter close", NULL},
3884: */
3885: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
3886: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
3887: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3888: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3889: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3890: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3891: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3892: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3893: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3894: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
3895: #ifdef SUPPORT_MSCDEX
3896: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3897: {0x65, "Not ready", "�������ł��Ă��܂���."},
3898: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3899: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3900: {0x68, "Door open", "���o�[���܂��Ă��܂���."
3901: #endif
3902: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3903: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3904: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3905: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3906: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3907: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3908: };
3909:
3910: static const struct {
3911: UINT16 code;
3912: char *message_english;
3913: char *message_japanese;
3914: } param_error_table[] = {
3915: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3916: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3917: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3918: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3919: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3920: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3921: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3922: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3923: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3924: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3925: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3926: };
3927:
3928: static const struct {
3929: UINT16 code;
3930: char *message_english;
3931: char *message_japanese;
3932: } critical_error_table[] = {
3933: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3934: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3935: {0x02, "Not ready", "�������ł��Ă��܂���."},
3936: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3937: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3938: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3939: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3940: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3941: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3942: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3943: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3944: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3945: {0x0C, "General failure", "�G���[�ł�."},
3946: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3947: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3948: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3949: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3950: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3951: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3952: {0x13, "Out of input", "���͂��I���܂���."},
3953: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3954: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3955: };
3956:
3957: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3958: int msdos_psp_get_file_table(int fd, int psp_seg);
3959: void msdos_putch(UINT8 data);
3960: void msdos_putch_fast(UINT8 data);
3961: #ifdef USE_SERVICE_THREAD
3962: void msdos_putch_tmp(UINT8 data);
3963: #endif
3964: const char *msdos_short_path(const char *path);
3965: bool msdos_is_valid_drive(int drv);
3966: bool msdos_is_removable_drive(int drv);
3967: bool msdos_is_cdrom_drive(int drv);
3968: bool msdos_is_remote_drive(int drv);
3969: bool msdos_is_subst_drive(int drv);
3970:
3971: // process info
3972:
3973: process_t *msdos_process_info_create(UINT16 psp_seg)
3974: {
3975: for(int i = 0; i < MAX_PROCESS; i++) {
3976: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3977: memset(&process[i], 0, sizeof(process_t));
3978: process[i].psp = psp_seg;
3979: return(&process[i]);
3980: }
3981: }
3982: fatalerror("too many processes\n");
3983: return(NULL);
3984: }
3985:
3986: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error = true)
3987: {
3988: for(int i = 0; i < MAX_PROCESS; i++) {
3989: if(process[i].psp == psp_seg) {
3990: return(&process[i]);
3991: }
3992: }
3993: if(show_error) {
3994: fatalerror("invalid psp address\n");
3995: }
3996: return(NULL);
3997: }
3998:
3999: void msdos_sda_update(int psp_seg)
4000: {
4001: sda_t *sda = (sda_t *)(mem + SDA_TOP);
4002:
4003: for(int i = 0; i < MAX_PROCESS; i++) {
4004: if(process[i].psp == psp_seg) {
4005: sda->switchar = process[i].switchar;
4006: sda->current_dta.w.l = process[i].dta.w.l;
4007: sda->current_dta.w.h = process[i].dta.w.h;
4008: sda->current_psp = process[i].psp;
4009: break;
4010: }
4011: }
4012: sda->malloc_strategy = malloc_strategy;
4013: sda->return_code = retval;
4014: sda->current_drive = _getdrive();
4015: }
4016:
4017: // dta info
4018:
4019: void msdos_dta_info_init()
4020: {
4021: for(int i = 0; i < MAX_DTAINFO; i++) {
4022: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
4023: }
4024: }
4025:
4026: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
4027: {
4028: dtainfo_t *free_dta = NULL;
4029: for(int i = 0; i < MAX_DTAINFO; i++) {
4030: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
4031: if(free_dta == NULL) {
4032: free_dta = &dtalist[i];
4033: }
4034: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
4035: return(&dtalist[i]);
4036: }
4037: }
4038: if(free_dta) {
4039: free_dta->psp = psp_seg;
4040: free_dta->dta = dta_laddr;
4041: return(free_dta);
4042: }
4043: fatalerror("too many dta\n");
4044: return(NULL);
4045: }
4046:
4047: void msdos_dta_info_free(UINT16 psp_seg)
4048: {
4049: for(int i = 0; i < MAX_DTAINFO; i++) {
4050: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
4051: FindClose(dtalist[i].find_handle);
4052: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
4053: }
4054: }
4055: }
4056:
4057: void msdos_cds_update(int drv)
4058: {
4059: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv);
4060:
4061: memset(cds, 0, 88);
4062:
4063: if(msdos_is_valid_drive(drv)) {
4064: char path[MAX_PATH];
4065: if(msdos_is_remote_drive(drv)) {
4066: cds->drive_attrib = 0xc000; // network drive
4067: } else if(msdos_is_subst_drive(drv)) {
4068: cds->drive_attrib = 0x5000; // subst drive
4069: } else {
4070: cds->drive_attrib = 0x4000; // physical drive
4071: }
4072: if(_getdcwd(drv + 1, path, MAX_PATH) != NULL) {
4073: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path));
4074: }
4075: }
4076: if(cds->path_name[0] == '\0') {
4077: sprintf(cds->path_name, "%c:\\", 'A' + drv);
4078: }
4079: cds->dpb_ptr.w.h = DPB_TOP >> 4;
4080: cds->dpb_ptr.w.l = sizeof(dpb_t) * drv;
4081: cds->word_1 = cds->word_2 = 0xffff;
4082: cds->word_3 = 0xffff; // stored user data from INT 21/AX=5F03h if this is network drive
4083: cds->bs_offset = 2;
4084: }
4085:
4086: void msdos_cds_update(int drv, const char *path)
4087: {
4088: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv);
4089:
4090: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path));
4091: }
4092:
4093: // nls information tables
4094:
4095: // uppercase table (func 6502h)
4096: void msdos_upper_table_update()
4097: {
4098: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
4099: for(unsigned i = 0; i < 0x80; ++i) {
4100: UINT8 c[4];
4101: *(UINT32 *)c = 0; // reset internal conversion state
4102: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
4103: c[0] = 0x80 + i;
4104: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
4105: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
4106: }
4107: }
4108:
4109: // lowercase table (func 6503h)
4110: void msdos_lower_table_update()
4111: {
4112: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
4113: for(unsigned i = 0; i < 0x80; ++i) {
4114: UINT8 c[4];
4115: *(UINT32 *)c = 0; // reset internal conversion state
4116: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
4117: c[0] = 0x80 + i;
4118: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
4119: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
4120: }
4121: }
4122:
4123: // filename uppercase table (func 6504h)
4124: void msdos_filename_upper_table_init()
4125: {
4126: // depended on (file)system, not on active codepage
4127: // temporary solution: just filling data
4128: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
4129: for(unsigned i = 0; i < 0x80; ++i) {
4130: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
4131: }
4132: }
4133:
4134: // filaname terminator table (func 6505h)
4135: void msdos_filename_terminator_table_init()
4136: {
4137: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
4138: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
4139:
4140: data[2] = 1; // marker? (permissible character value)
4141: data[3] = 0x00; // 00h...FFh
4142: data[4] = 0xff;
4143: data[5] = 0; // marker? (excluded character)
4144: data[6] = 0x00; // 00h...20h
4145: data[7] = 0x20;
4146: data[8] = 2; // marker? (illegal characters for filename)
4147: data[9] = (UINT8)strlen(illegal_chars);
4148: memcpy(data + 10, illegal_chars, data[9]);
4149:
4150: // total length
4151: *(UINT16 *)data = (10 - 2) + data[9];
4152: }
4153:
4154: // collating table (func 6506h)
4155: void msdos_collating_table_update()
4156: {
4157: // temporary solution: just filling data
4158: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
4159: for(unsigned i = 0; i < 256; ++i) {
4160: mem[COLLATING_TABLE_TOP + 2 + i] = i;
4161: }
4162: }
4163:
4164: // dbcs
4165:
4166: void msdos_dbcs_table_update()
4167: {
4168: UINT8 dbcs_data[DBCS_SIZE];
4169: memset(dbcs_data, 0, sizeof(dbcs_data));
4170:
4171: CPINFO info;
4172: GetCPInfo(active_code_page, &info);
4173:
4174: if(info.MaxCharSize != 1) {
4175: for(int i = 0;; i += 2) {
4176: UINT8 lo = info.LeadByte[i + 0];
4177: UINT8 hi = info.LeadByte[i + 1];
4178: dbcs_data[2 + i + 0] = lo;
4179: dbcs_data[2 + i + 1] = hi;
4180: if(lo == 0 && hi == 0) {
4181: dbcs_data[0] = i + 2;
4182: break;
4183: }
4184: }
4185: } else {
4186: dbcs_data[0] = 2; // ???
4187: }
4188: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
4189: }
4190:
4191: void msdos_dbcs_table_finish()
4192: {
4193: if(system_code_page != _getmbcp()) {
4194: _setmbcp(system_code_page);
4195: }
4196: if(console_code_page != GetConsoleCP()) {
4197: SetConsoleCP(console_code_page);
4198: SetConsoleOutputCP(console_code_page);
4199: }
4200: }
4201:
4202: void msdos_nls_tables_init()
4203: {
4204: active_code_page = console_code_page = GetConsoleCP();
4205: system_code_page = _getmbcp();
4206:
4207: if(active_code_page != system_code_page) {
4208: if(_setmbcp(active_code_page) != 0) {
4209: active_code_page = system_code_page;
4210: }
4211: }
4212:
4213: msdos_upper_table_update();
4214: msdos_lower_table_update();
4215: msdos_filename_terminator_table_init();
4216: msdos_filename_upper_table_init();
4217: msdos_collating_table_update();
4218: msdos_dbcs_table_update();
4219: }
4220:
4221: void msdos_nls_tables_update()
4222: {
4223: msdos_dbcs_table_update();
4224: msdos_upper_table_update();
4225: msdos_lower_table_update();
4226: // msdos_collating_table_update();
4227: }
4228:
4229: int msdos_lead_byte_check(UINT8 code)
4230: {
4231: UINT8 *dbcs_table = mem + DBCS_TABLE;
4232:
4233: for(int i = 0;; i += 2) {
4234: UINT8 lo = dbcs_table[i + 0];
4235: UINT8 hi = dbcs_table[i + 1];
4236: if(lo == 0 && hi == 0) {
4237: break;
4238: }
4239: if(lo <= code && code <= hi) {
4240: return(1);
4241: }
4242: }
4243: return(0);
4244: }
4245:
4246: int msdos_ctrl_code_check(UINT8 code)
4247: {
4248: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
4249: }
4250:
4251: int msdos_kanji_2nd_byte_check(UINT8 *buf, int n)
4252: {
4253: int is_kanji_1st = 0;
4254: int is_kanji_2nd = 0;
4255:
4256: for(int p = 0;; p++) {
4257: if(is_kanji_1st) {
4258: is_kanji_1st = 0;
4259: is_kanji_2nd = 1;
4260: } else if(msdos_lead_byte_check(buf[p])) {
4261: is_kanji_1st = 1;
4262: }
4263: if(p == n) {
4264: return(is_kanji_2nd);
4265: }
4266: is_kanji_2nd = 0;
4267: }
4268: }
4269:
4270: // file control
4271:
4272: const char *msdos_remove_double_quote(const char *path)
4273: {
4274: static char tmp[MAX_PATH];
4275:
4276: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
4277: memset(tmp, 0, sizeof(tmp));
4278: memcpy(tmp, path + 1, strlen(path) - 2);
4279: } else {
4280: strcpy(tmp, path);
4281: }
4282: return(tmp);
4283: }
4284:
4285: const char *msdos_remove_end_separator(const char *path)
4286: {
4287: static char tmp[MAX_PATH];
4288:
4289: strcpy(tmp, path);
4290:
4291: // for example "C:\" case, the end separator should not be removed
4292: if(strlen(tmp) > 3 && tmp[strlen(tmp) - 1] == '\\') {
4293: tmp[strlen(tmp) - 1] = '\0';
4294: }
4295: return(tmp);
4296: }
4297:
4298: const char *msdos_combine_path(const char *dir, const char *file)
4299: {
4300: static char tmp[MAX_PATH];
4301: const char *tmp_dir = msdos_remove_double_quote(dir);
4302:
4303: if(strlen(tmp_dir) == 0) {
4304: strcpy(tmp, file);
4305: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
4306: sprintf(tmp, "%s%s", tmp_dir, file);
4307: } else {
4308: sprintf(tmp, "%s\\%s", tmp_dir, file);
4309: }
4310: return(tmp);
4311: }
4312:
4313: const char *msdos_trimmed_path(const char *path, int lfn)
4314: {
4315: static char tmp[MAX_PATH];
4316:
4317: if(lfn) {
4318: strcpy(tmp, path);
4319: } else {
4320: // remove space in the path
4321: const char *src = path;
4322: char *dst = tmp;
4323:
4324: while(*src != '\0') {
4325: if(msdos_lead_byte_check(*src)) {
4326: *dst++ = *src++;
4327: *dst++ = *src++;
4328: } else if(*src != ' ') {
4329: *dst++ = *src++;
4330: } else {
4331: src++; // skip space
4332: }
4333: }
4334: *dst = '\0';
4335: }
4336: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
4337: // redirect C:\COMMAND.COM to comspec_path
4338: strcpy(tmp, comspec_path);
4339: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
4340: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
4341: static int root_drive_protected = -1;
4342: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
4343: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
4344:
4345: if(GetFullPathNameA(tmp, MAX_PATH, temp, &name_temp) != 0 &&
4346: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
4347: strcpy(name, name_temp);
4348: name_temp[0] = '\0';
4349:
4350: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
4351: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
4352: if(root_drive_protected == -1) {
4353: FILE *fp = NULL;
4354:
4355: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
4356: root_drive_protected = 1;
4357: try {
4358: if((fp = fopen(temp, "w")) != NULL) {
4359: if(fprintf(fp, "TEST") == 4) {
4360: root_drive_protected = 0;
4361: }
4362: }
4363: } catch(...) {
4364: }
4365: if(fp != NULL) {
4366: fclose(fp);
4367: }
4368: if(_access(temp, 0) == 0) {
4369: remove(temp);
4370: }
4371: }
4372: if(root_drive_protected == 1) {
4373: if(GetEnvironmentVariableA("TEMP", temp, MAX_PATH) != 0 ||
4374: GetEnvironmentVariableA("TMP", temp, MAX_PATH) != 0) {
4375: strcpy(tmp, msdos_combine_path(temp, name));
4376: }
4377: }
4378: }
4379: }
4380: }
4381: return(tmp);
4382: }
4383:
4384: const char *msdos_get_multiple_short_path(const char *src)
4385: {
4386: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
4387: static char env_path[ENV_SIZE];
4388: char tmp[ENV_SIZE], *token;
4389:
4390: memset(env_path, 0, sizeof(env_path));
4391: strcpy(tmp, src);
4392: token = my_strtok(tmp, ";");
4393:
4394: while(token != NULL) {
4395: if(token[0] != '\0') {
4396: const char *path = msdos_remove_double_quote(token);
4397: char short_path[MAX_PATH];
4398: if(path != NULL && strlen(path) != 0) {
4399: if(env_path[0] != '\0') {
4400: strcat(env_path, ";");
4401: }
4402: if(GetShortPathNameA(path, short_path, MAX_PATH) == 0) {
4403: strcat(env_path, msdos_remove_end_separator(path));
4404: } else {
4405: my_strupr(short_path);
4406: strcat(env_path, msdos_remove_end_separator(short_path));
4407: }
4408: }
4409: }
4410: token = my_strtok(NULL, ";");
4411: }
4412: return(env_path);
4413: }
4414:
4415: bool match(const char *text, const char *pattern)
4416: {
4417: // http://www.prefield.com/algorithm/string/wildcard.html
4418: switch(*pattern) {
4419: case '\0':
4420: return !*text;
4421: case '*':
4422: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
4423: case '?':
4424: return *text && match(text + 1, pattern + 1);
4425: default:
4426: return (*text == *pattern) && match(text + 1, pattern + 1);
4427: }
4428: }
4429:
4430: bool msdos_match_volume_label(const char *path, const char *volume)
4431: {
4432: const char *p = NULL;
4433:
4434: if(!*volume) {
4435: return false;
4436: } else if((p = my_strchr(path, ':')) != NULL) {
4437: return msdos_match_volume_label(p + 1, volume);
4438: } else if((p = my_strchr(path, '\\')) != NULL) {
4439: return msdos_match_volume_label(p + 1, volume);
4440: } else if((p = my_strchr(path, '.')) != NULL) {
4441: char tmp[MAX_PATH];
4442: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
4443: return match(volume, tmp);
4444: } else {
4445: return match(volume, path);
4446: }
4447: }
4448:
4449: const char *msdos_fcb_path(fcb_t *fcb)
4450: {
4451: static char tmp[MAX_PATH];
4452: char name[9], ext[4];
4453:
4454: memset(name, 0, sizeof(name));
4455: memcpy(name, fcb->file_name, 8);
4456: strcpy(name, msdos_trimmed_path(name, 0));
4457:
4458: memset(ext, 0, sizeof(ext));
4459: memcpy(ext, fcb->file_name + 8, 3);
4460: strcpy(ext, msdos_trimmed_path(ext, 0));
4461:
4462: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
4463: strcpy(name, "*");
4464: }
4465: if(ext[0] == '\0') {
4466: strcpy(tmp, name);
4467: } else {
4468: if(strcmp(ext, "???") == 0) {
4469: strcpy(ext, "*");
4470: }
4471: sprintf(tmp, "%s.%s", name, ext);
4472: }
4473: return(tmp);
4474: }
4475:
4476: void msdos_set_fcb_path(fcb_t *fcb, const char *path)
4477: {
4478: char tmp[MAX_PATH];
4479: strcpy(tmp, path);
4480: char *ext = my_strchr(tmp, '.');
4481:
4482: memset(fcb->file_name, 0x20, 8 + 3);
4483: if(ext != NULL && tmp[0] != '.') {
4484: *ext = '\0';
4485: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
4486: }
4487: memcpy(fcb->file_name, tmp, strlen(tmp));
4488: }
4489:
4490: const char *msdos_short_path(const char *path)
4491: {
4492: static char tmp[MAX_PATH];
4493:
4494: if(GetShortPathNameA(path, tmp, MAX_PATH) == 0) {
4495: strcpy(tmp, path);
4496: }
4497: my_strupr(tmp);
4498: return(tmp);
4499: }
4500:
4501: const char *msdos_short_name(WIN32_FIND_DATAA *fd)
4502: {
4503: static char tmp[MAX_PATH];
4504:
4505: if(fd->cAlternateFileName[0]) {
4506: strcpy(tmp, fd->cAlternateFileName);
4507: } else {
4508: strcpy(tmp, fd->cFileName);
4509: }
4510: my_strupr(tmp);
4511: return(tmp);
4512: }
4513:
4514: const char *msdos_short_full_path(const char *path)
4515: {
4516: static char tmp[MAX_PATH];
4517: char full[MAX_PATH], *name;
4518:
4519: // Full works with non-existent files, but Short does not
4520: GetFullPathNameA(path, MAX_PATH, full, &name);
4521: *tmp = '\0';
4522: if(GetShortPathNameA(full, tmp, MAX_PATH) == 0 && name > path) {
4523: name[-1] = '\0';
4524: DWORD len = GetShortPathNameA(full, tmp, MAX_PATH);
4525: if(len == 0) {
4526: strcpy(tmp, full);
4527: } else {
4528: tmp[len++] = '\\';
4529: strcpy(tmp + len, name);
4530: }
4531: }
4532: my_strupr(tmp);
4533: return(tmp);
4534: }
4535:
4536: const char *msdos_short_full_dir(const char *path)
4537: {
4538: static char tmp[MAX_PATH];
4539: char full[MAX_PATH], *name;
4540:
4541: GetFullPathNameA(path, MAX_PATH, full, &name);
4542: name[-1] = '\0';
4543: if(GetShortPathNameA(full, tmp, MAX_PATH) == 0) {
4544: strcpy(tmp, full);
4545: }
4546: my_strupr(tmp);
4547: return(tmp);
4548: }
4549:
4550: const char *msdos_local_file_path(const char *path, int lfn)
4551: {
4552: static char trimmed[MAX_PATH];
4553:
4554: strcpy(trimmed, msdos_trimmed_path(path, lfn));
4555: #if 0
4556: // I have forgotten the reason of this routine... :-(
4557: if(_access(trimmed, 0) != 0) {
4558: process_t *process = msdos_process_info_get(current_psp);
4559: static char tmp[MAX_PATH];
4560:
4561: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
4562: if(_access(tmp, 0) == 0) {
4563: return(tmp);
4564: }
4565: }
4566: #endif
4567: return(trimmed);
4568: }
4569:
4570: bool msdos_is_device_path(const char *path)
4571: {
4572: char full[MAX_PATH], *name;
4573:
4574: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) {
4575: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4576: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4577: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4578: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4579: _stricmp(full, "\\\\.\\COM1") == 0 ||
4580: _stricmp(full, "\\\\.\\COM2") == 0 ||
4581: _stricmp(full, "\\\\.\\COM3") == 0 ||
4582: _stricmp(full, "\\\\.\\COM4") == 0 ||
4583: _stricmp(full, "\\\\.\\COM5") == 0 ||
4584: _stricmp(full, "\\\\.\\COM6") == 0 ||
4585: _stricmp(full, "\\\\.\\COM7") == 0 ||
4586: _stricmp(full, "\\\\.\\COM8") == 0 ||
4587: _stricmp(full, "\\\\.\\COM9") == 0 ||
4588: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4589: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4590: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4591: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4592: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4593: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4594: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4595: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4596: _stricmp(full, "\\\\.\\LPT9") == 0) {
4597: return(true);
4598: } else if(name != NULL) {
4599: if(_stricmp(name, "CLOCK$" ) == 0 ||
4600: _stricmp(name, "CONFIG$" ) == 0 ||
4601: _stricmp(name, "EMMXXXX0") == 0 ||
4602: // _stricmp(name, "SCSIMGR$") == 0 ||
4603: _stricmp(name, "$IBMAIAS") == 0) {
4604: return(true);
4605: }
4606: }
4607: }
4608: return(false);
4609: }
4610:
4611: bool msdos_is_con_path(const char *path)
4612: {
4613: char full[MAX_PATH], *name;
4614:
4615: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) {
4616: return(_stricmp(full, "\\\\.\\CON") == 0);
4617: }
4618: return(false);
4619: }
4620:
4621: int msdos_is_comm_path(const char *path)
4622: {
4623: char full[MAX_PATH], *name;
4624:
4625: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) {
4626: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4627: return(1);
4628: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4629: return(2);
4630: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4631: return(3);
4632: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4633: return(4);
4634: }
4635: }
4636: return(0);
4637: }
4638:
4639: void msdos_set_comm_params(int sio_port, const char *path)
4640: {
4641: // COM1:{110,150,300,600,1200,2400,4800,9600},{N,O,E,M,S},{8,7,6,5},{1,1.5,2}
4642: const char *p = NULL;
4643:
4644: if((p = strstr(path, ":")) != NULL) {
4645: UINT8 selector = sio_read(sio_port - 1, 3);
4646:
4647: // baud rate
4648: int baud = max(110, min(9600, atoi(p + 1)));
4649: UINT16 divisor = 115200 / baud;
4650:
4651: if((p = strstr(p + 1, ",")) != NULL) {
4652: // parity
4653: if(p[1] == 'N' || p[1] == 'n') {
4654: selector = (selector & ~0x38) | 0x00;
4655: } else if(p[1] == 'O' || p[1] == 'o') {
4656: selector = (selector & ~0x38) | 0x08;
4657: } else if(p[1] == 'E' || p[1] == 'e') {
4658: selector = (selector & ~0x38) | 0x18;
4659: } else if(p[1] == 'M' || p[1] == 'm') {
4660: selector = (selector & ~0x38) | 0x28;
4661: } else if(p[1] == 'S' || p[1] == 's') {
4662: selector = (selector & ~0x38) | 0x38;
4663: }
4664: if((p = strstr(p + 1, ",")) != NULL) {
4665: // word length
4666: if(p[1] == '8') {
4667: selector = (selector & ~0x03) | 0x03;
4668: } else if(p[1] == '7') {
4669: selector = (selector & ~0x03) | 0x02;
4670: } else if(p[1] == '6') {
4671: selector = (selector & ~0x03) | 0x01;
4672: } else if(p[1] == '5') {
4673: selector = (selector & ~0x03) | 0x00;
4674: }
4675: if((p = strstr(p + 1, ",")) != NULL) {
4676: // stop bits
4677: float bits = atof(p + 1);
4678: if(bits > 1.0F) {
4679: selector |= 0x04;
4680: } else {
4681: selector &= ~0x04;
4682: }
4683: }
4684: }
4685: }
4686: sio_write(sio_port - 1, 3, selector | 0x80);
4687: sio_write(sio_port - 1, 0, divisor & 0xff);
4688: sio_write(sio_port - 1, 1, divisor >> 8);
4689: sio_write(sio_port - 1, 3, selector);
4690: }
4691: }
4692:
4693: int msdos_is_prn_path(const char *path)
4694: {
4695: char full[MAX_PATH], *name;
4696:
4697: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) {
4698: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4699: return(1);
4700: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4701: return(1);
4702: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4703: return(2);
4704: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4705: return(3);
4706: }
4707: }
4708: return(0);
4709: }
4710:
4711: bool msdos_is_valid_drive(int drv)
4712: {
4713: return(drv >= 0 && drv < 26 && (GetLogicalDrives() & (1 << drv)) != 0);
4714: }
4715:
4716: bool msdos_is_removable_drive(int drv)
4717: {
4718: char volume[] = "A:\\";
4719:
4720: volume[0] = 'A' + drv;
4721:
4722: return(GetDriveTypeA(volume) == DRIVE_REMOVABLE);
4723: }
4724:
4725: bool msdos_is_cdrom_drive(int drv)
4726: {
4727: char volume[] = "A:\\";
4728:
4729: volume[0] = 'A' + drv;
4730:
4731: return(GetDriveTypeA(volume) == DRIVE_CDROM);
4732: }
4733:
4734: bool msdos_is_remote_drive(int drv)
4735: {
4736: char volume[] = "A:\\";
4737:
4738: volume[0] = 'A' + drv;
4739:
4740: return(GetDriveTypeA(volume) == DRIVE_REMOTE);
4741: }
4742:
4743: bool msdos_is_subst_drive(int drv)
4744: {
4745: char device[] = "A:", path[MAX_PATH];
4746:
4747: device[0] = 'A' + drv;
4748:
4749: if(QueryDosDeviceA(device, path, MAX_PATH)) {
4750: if(strncmp(path, "\\??\\", 4) == 0) {
4751: return(true);
4752: }
4753: }
4754: return(false);
4755: }
4756:
4757: bool msdos_is_existing_file(const char *path)
4758: {
4759: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4760: WIN32_FIND_DATAA fd;
4761: HANDLE hFind;
4762:
4763: if((hFind = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) {
4764: FindClose(hFind);
4765: return((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
4766: }
4767: return(false);
4768: }
4769:
4770: bool msdos_is_existing_dir(const char *path)
4771: {
4772: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4773: WIN32_FIND_DATAA fd;
4774: HANDLE hFind;
4775:
4776: if((hFind = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) {
4777: FindClose(hFind);
4778: return((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
4779: }
4780: return(false);
4781: }
4782:
4783: const char *msdos_search_command_com(const char *command_path, const char *env_path)
4784: {
4785: static char tmp[MAX_PATH];
4786: char path[ENV_SIZE], *file_name;
4787:
4788: // check if COMMAND.COM is in the same directory as the target program file
4789: if(GetFullPathNameA(command_path, MAX_PATH, tmp, &file_name) != 0) {
4790: sprintf(file_name, "COMMAND.COM");
4791: if(_access(tmp, 0) == 0) {
4792: return(tmp);
4793: }
4794: }
4795:
4796: // check if COMMAND.COM is in the same directory as the running msdos.exe
4797: if(GetModuleFileNameA(NULL, path, MAX_PATH) != 0 && GetFullPathNameA(path, MAX_PATH, tmp, &file_name) != 0) {
4798: sprintf(file_name, "COMMAND.COM");
4799: if(_access(tmp, 0) == 0) {
4800: return(tmp);
4801: }
4802: }
4803:
4804: // check if COMMAND.COM is in the current directory
4805: if(GetFullPathNameA("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4806: if(_access(tmp, 0) == 0) {
4807: return(tmp);
4808: }
4809: }
4810:
4811: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4812: strcpy(path, env_path);
4813: char *token = my_strtok(path, ";");
4814: while(token != NULL) {
4815: if(strlen(token) != 0 && token[0] != '%') {
4816: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4817: if(_access(tmp, 0) == 0) {
4818: return(tmp);
4819: }
4820: }
4821: token = my_strtok(NULL, ";");
4822: }
4823: return(NULL);
4824: }
4825:
4826: int msdos_drive_number(const char *path)
4827: {
4828: char tmp[MAX_PATH], *name;
4829:
4830: if(GetFullPathNameA(path, MAX_PATH, tmp, &name) >= 2 && tmp[1] == ':') {
4831: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4832: return(tmp[0] - 'a');
4833: } else if(tmp[0] >= 'A' && tmp[0] <= 'Z') {
4834: return(tmp[0] - 'A');
4835: }
4836: }
4837: // return(msdos_drive_number("."));
4838: return(_getdrive() - 1);
4839: }
4840:
4841: const char *msdos_volume_label(const char *path)
4842: {
4843: static char tmp[MAX_PATH];
4844: char volume[] = "A:\\";
4845:
4846: if(path[1] == ':') {
4847: volume[0] = path[0];
4848: } else {
4849: volume[0] = 'A' + _getdrive() - 1;
4850: }
4851: if(!GetVolumeInformationA(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4852: memset(tmp, 0, sizeof(tmp));
4853: }
4854: return(tmp);
4855: }
4856:
4857: const char *msdos_short_volume_label(const char *label)
4858: {
4859: static char tmp[(8 + 1 + 3) + 1];
4860: const char *src = label;
4861: int remain = strlen(label);
4862: char *dst_n = tmp;
4863: char *dst_e = tmp + 9;
4864:
4865: strcpy(tmp, " . ");
4866: for(int i = 0; i < 8 && remain > 0; i++) {
4867: if(msdos_lead_byte_check(*src)) {
4868: if(++i == 8) {
4869: break;
4870: }
4871: *dst_n++ = *src++;
4872: remain--;
4873: }
4874: *dst_n++ = *src++;
4875: remain--;
4876: }
4877: if(remain > 0) {
4878: for(int i = 0; i < 3 && remain > 0; i++) {
4879: if(msdos_lead_byte_check(*src)) {
4880: if(++i == 3) {
4881: break;
4882: }
4883: *dst_e++ = *src++;
4884: remain--;
4885: }
4886: *dst_e++ = *src++;
4887: remain--;
4888: }
4889: *dst_e = '\0';
4890: } else {
4891: *dst_n = '\0';
4892: }
4893: my_strupr(tmp);
4894: return(tmp);
4895: }
4896:
4897: errno_t msdos_maperr(unsigned long oserrno)
4898: {
4899: _doserrno = oserrno;
4900: switch(oserrno) {
4901: case ERROR_FILE_NOT_FOUND: // 2
4902: case ERROR_PATH_NOT_FOUND: // 3
4903: case ERROR_INVALID_DRIVE: // 15
4904: case ERROR_NO_MORE_FILES: // 18
4905: case ERROR_BAD_NETPATH: // 53
4906: case ERROR_BAD_NET_NAME: // 67
4907: case ERROR_BAD_PATHNAME: // 161
4908: case ERROR_FILENAME_EXCED_RANGE: // 206
4909: return ENOENT;
4910: case ERROR_TOO_MANY_OPEN_FILES: // 4
4911: return EMFILE;
4912: case ERROR_ACCESS_DENIED: // 5
4913: case ERROR_CURRENT_DIRECTORY: // 16
4914: case ERROR_NETWORK_ACCESS_DENIED: // 65
4915: case ERROR_CANNOT_MAKE: // 82
4916: case ERROR_FAIL_I24: // 83
4917: case ERROR_DRIVE_LOCKED: // 108
4918: case ERROR_SEEK_ON_DEVICE: // 132
4919: case ERROR_NOT_LOCKED: // 158
4920: case ERROR_LOCK_FAILED: // 167
4921: return EACCES;
4922: case ERROR_INVALID_HANDLE: // 6
4923: case ERROR_INVALID_TARGET_HANDLE: // 114
4924: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4925: return EBADF;
4926: case ERROR_ARENA_TRASHED: // 7
4927: case ERROR_NOT_ENOUGH_MEMORY: // 8
4928: case ERROR_INVALID_BLOCK: // 9
4929: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4930: return ENOMEM;
4931: case ERROR_BAD_ENVIRONMENT: // 10
4932: return E2BIG;
4933: case ERROR_BAD_FORMAT: // 11
4934: return ENOEXEC;
4935: case ERROR_NOT_SAME_DEVICE: // 17
4936: return EXDEV;
4937: case ERROR_FILE_EXISTS: // 80
4938: case ERROR_ALREADY_EXISTS: // 183
4939: return EEXIST;
4940: case ERROR_NO_PROC_SLOTS: // 89
4941: case ERROR_MAX_THRDS_REACHED: // 164
4942: case ERROR_NESTING_NOT_ALLOWED: // 215
4943: return EAGAIN;
4944: case ERROR_BROKEN_PIPE: // 109
4945: return EPIPE;
4946: case ERROR_DISK_FULL: // 112
4947: return ENOSPC;
4948: case ERROR_WAIT_NO_CHILDREN: // 128
4949: case ERROR_CHILD_NOT_COMPLETE: // 129
4950: return ECHILD;
4951: case ERROR_DIR_NOT_EMPTY: // 145
4952: return ENOTEMPTY;
4953: }
4954: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
4955: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4956: return EACCES;
4957: }
4958: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
4959: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4960: return ENOEXEC;
4961: }
4962: return EINVAL;
4963: }
4964:
4965: int msdos_open(const char *path, int oflag)
4966: {
4967: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
4968: return(_open(path, oflag));
4969: }
4970:
4971: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
4972: DWORD disposition;
4973: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4974: default:
4975: case _O_EXCL:
4976: disposition = OPEN_EXISTING;
4977: break;
4978: case _O_CREAT:
4979: disposition = OPEN_ALWAYS;
4980: break;
4981: case _O_CREAT | _O_EXCL:
4982: case _O_CREAT | _O_TRUNC | _O_EXCL:
4983: disposition = CREATE_NEW;
4984: break;
4985: case _O_TRUNC:
4986: case _O_TRUNC | _O_EXCL:
4987: disposition = TRUNCATE_EXISTING;
4988: break;
4989: case _O_CREAT | _O_TRUNC:
4990: disposition = CREATE_ALWAYS;
4991: break;
4992: }
4993:
4994: HANDLE h = CreateFileA(path, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
4995: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4996: FILE_ATTRIBUTE_NORMAL, NULL);
4997: if(h == INVALID_HANDLE_VALUE) {
4998: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4999: // Retry without FILE_WRITE_ATTRIBUTES.
5000: h = CreateFileA(path, GENERIC_READ,
5001: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
5002: FILE_ATTRIBUTE_NORMAL, NULL);
5003: if(h == INVALID_HANDLE_VALUE) {
5004: errno = msdos_maperr(GetLastError());
5005: return(-1);
5006: }
5007: }
5008:
5009: int fd = _open_osfhandle((intptr_t) h, oflag);
5010: if(fd == -1) {
5011: CloseHandle(h);
5012: }
5013: return(fd);
5014: }
5015:
5016: int msdos_open_device(const char *path, int oflag, int *sio_port, int *lpt_port)
5017: {
5018: int fd = -1;
5019:
5020: *sio_port = *lpt_port = 0;
5021:
5022: if(msdos_is_con_path(path)) {
5023: // MODE.COM opens CON device with read/write mode :-(
5024: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) == _O_RDWR) {
5025: oflag &= ~(_O_RDONLY | _O_WRONLY | _O_RDWR);
5026: oflag |= _O_RDONLY;
5027: }
5028: if((fd = msdos_open("CON", oflag)) == -1) {
5029: // fd = msdos_open("NUL", oflag);
5030: }
5031: } else if((*sio_port = msdos_is_comm_path(path)) != 0) {
5032: fd = msdos_open("NUL", oflag);
5033: msdos_set_comm_params(*sio_port, path);
5034: } else if((*lpt_port = msdos_is_prn_path(path)) != 0) {
5035: fd = msdos_open("NUL", oflag);
5036: } else if(msdos_is_device_path(path)) {
5037: fd = msdos_open("NUL", oflag);
5038: // } else if(oflag & _O_CREAT) {
5039: // fd = _open(path, oflag, _S_IREAD | _S_IWRITE);
5040: // } else {
5041: // fd = _open(path, oflag);
5042: }
5043: return(fd);
5044: }
5045:
5046: UINT16 msdos_device_info(const char *path)
5047: {
5048: if(msdos_is_con_path(path)) {
5049: return(0x80d3);
5050: } else if(msdos_is_comm_path(path)) {
5051: return(0x80a0);
5052: } else if(msdos_is_prn_path(path)) {
5053: // return(0xa8c0);
5054: return(0x80a0);
5055: } else if(msdos_is_device_path(path)) {
5056: if(strstr(path, "EMMXXXX0") != NULL) {
5057: return(0xc0c0);
5058: } else if(strstr(path, "MSCD001") != NULL) {
5059: return(0xc880);
5060: } else {
5061: return(0x8084);
5062: }
5063: } else {
5064: return(msdos_drive_number(path));
5065: }
5066: }
5067:
5068: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg, int sio_port = 0, int lpt_port = 0)
5069: {
5070: static int id = 0;
5071: char full[MAX_PATH], *name;
5072:
5073: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) {
5074: strcpy(file_handler[fd].path, full);
5075: } else {
5076: strcpy(file_handler[fd].path, path);
5077: }
5078: // isatty makes no distinction between CON & NUL
5079: // GetFileSize fails on CON, succeeds on NUL
5080: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
5081: if(info == 0x80d3) {
5082: info = 0x8084;
5083: }
5084: atty = 0;
5085: } else if(!atty && info == 0x80d3) {
5086: // info = msdos_drive_number(".");
5087: info = msdos_drive_number(path);
5088: }
5089: file_handler[fd].valid = 1;
5090: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
5091: file_handler[fd].atty = (sio_port == 0 && lpt_port == 0) ? atty : 0;
5092: file_handler[fd].mode = mode;
5093: file_handler[fd].info = info;
5094: file_handler[fd].psp = psp_seg;
5095: file_handler[fd].sio_port = sio_port;
5096: file_handler[fd].lpt_port = lpt_port;
5097:
5098: // init system file table
5099: if(fd < 20) {
5100: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
5101:
5102: memset(sft, 0, 0x3b);
5103:
5104: *(UINT16 *)(sft + 0x00) = 1;
5105: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
5106: *(UINT8 *)(sft + 0x04) = GetFileAttributesA(file_handler[fd].path) & 0xff;
5107: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
5108:
5109: if(!(file_handler[fd].info & 0x80)) {
5110: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
5111: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
5112:
5113: FILETIME time, local;
5114: HANDLE hHandle;
5115: WORD dos_date = 0, dos_time = 0;
5116: DWORD file_size = 0;
5117: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
5118: if(GetFileTime(hHandle, NULL, NULL, &time)) {
5119: FileTimeToLocalFileTime(&time, &local);
5120: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
5121: }
5122: file_size = GetFileSize(hHandle, NULL);
5123: }
5124: *(UINT16 *)(sft + 0x0d) = dos_time;
5125: *(UINT16 *)(sft + 0x0f) = dos_date;
5126: *(UINT32 *)(sft + 0x11) = file_size;
5127: }
5128:
5129: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
5130: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
5131: my_strupr(fname);
5132: my_strupr(ext);
5133: memset(sft + 0x20, 0x20, 11);
5134: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
5135: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
5136:
5137: *(UINT16 *)(sft + 0x31) = psp_seg;
5138: }
5139: }
5140:
5141: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
5142: {
5143: strcpy(file_handler[dst].path, file_handler[src].path);
5144: file_handler[dst].valid = 1;
5145: file_handler[dst].id = file_handler[src].id;
5146: file_handler[dst].atty = file_handler[src].atty;
5147: file_handler[dst].mode = file_handler[src].mode;
5148: file_handler[dst].info = file_handler[src].info;
5149: file_handler[dst].psp = psp_seg;
5150: file_handler[dst].sio_port = file_handler[src].sio_port;
5151: file_handler[dst].lpt_port = file_handler[src].lpt_port;
5152: }
5153:
5154: void msdos_file_handler_close(int fd)
5155: {
5156: file_handler[fd].valid = 0;
5157:
5158: if(fd < 20) {
5159: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
5160: }
5161: }
5162:
5163: inline int msdos_file_attribute_create(UINT16 new_attr)
5164: {
5165: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
5166: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
5167: FILE_ATTRIBUTE_DIRECTORY));
5168: }
5169:
5170: // find file
5171:
5172: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
5173: {
5174: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
5175: return(0); // search directory only !!!
5176: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
5177: return(0);
5178: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
5179: return(0);
5180: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
5181: return(0);
5182: } else if((attribute & required_mask) != required_mask) {
5183: return(0);
5184: } else {
5185: return(1);
5186: }
5187: }
5188:
5189: int msdos_find_file_has_8dot3name(WIN32_FIND_DATAA *fd)
5190: {
5191: if(fd->cAlternateFileName[0]) {
5192: return(1);
5193: }
5194: size_t len = strlen(fd->cFileName);
5195: if(len > 12) {
5196: return(0);
5197: }
5198: const char *ext = strrchr(fd->cFileName, '.');
5199: if((ext ? ext - fd->cFileName : len) > 8) {
5200: return(0);
5201: }
5202: return(1);
5203: }
5204:
5205: void msdos_find_file_conv_local_time(WIN32_FIND_DATAA *fd)
5206: {
5207: FILETIME local;
5208:
5209: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
5210: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
5211: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
5212:
5213: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
5214: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
5215: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
5216:
5217: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
5218: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
5219: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
5220: }
5221:
5222: // i/o
5223:
5224: void msdos_stdio_reopen()
5225: {
5226: if(!file_handler[0].valid) {
5227: _dup2(DUP_STDIN, 0);
5228: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
5229: }
5230: if(!file_handler[1].valid) {
5231: _dup2(DUP_STDOUT, 1);
5232: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
5233: }
5234: if(!file_handler[2].valid) {
5235: _dup2(DUP_STDERR, 2);
5236: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
5237: }
5238: if(!file_handler[3].valid) {
5239: _dup2(DUP_STDAUX, 3);
5240: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
5241: }
5242: if(!file_handler[4].valid) {
5243: _dup2(DUP_STDPRN, 4);
5244: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
5245: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1
5246: }
5247: for(int i = 0; i < 5; i++) {
5248: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
5249: msdos_psp_set_file_table(i, i, current_psp);
5250: }
5251: }
5252: }
5253:
5254: int msdos_read(int fd, void *buffer, unsigned int count)
5255: {
5256: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
5257: // read from serial port
5258: int read = 0;
5259: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
5260: UINT8 *buf = (UINT8 *)buffer;
5261: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
5262: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
5263: DWORD timeout = timeGetTime() + 1000;
5264: while(read < count) {
5265: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x01) {
5266: buf[read++] = sio_read(file_handler[fd].sio_port - 1, 0);
5267: timeout = timeGetTime() + 1000;
5268: } else {
5269: if(timeGetTime() > timeout) {
5270: break;
5271: }
5272: Sleep(10);
5273: }
5274: }
5275: sio_write(file_handler[fd].sio_port - 1, 3, selector);
5276: }
5277: return(read);
5278: }
5279: return(_read(fd, buffer, count));
5280: }
5281:
5282: int msdos_kbhit()
5283: {
5284: msdos_stdio_reopen();
5285:
5286: process_t *process = msdos_process_info_get(current_psp);
5287: int fd = msdos_psp_get_file_table(0, current_psp);
5288:
5289: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
5290: // stdin is redirected to file
5291: return(eof(fd) == 0);
5292: }
5293:
5294: // check keyboard status
5295: if(key_recv != 0) {
5296: return(1);
5297: }
5298: if(key_buf_char != NULL && key_buf_scan != NULL) {
5299: #ifdef USE_SERVICE_THREAD
5300: EnterCriticalSection(&key_buf_crit_sect);
5301: #endif
5302: bool empty = pcbios_is_key_buffer_empty();
5303: #ifdef USE_SERVICE_THREAD
5304: LeaveCriticalSection(&key_buf_crit_sect);
5305: #endif
5306: if(!empty) return(1);
5307: }
5308: return(_kbhit());
5309: }
5310:
5311: int msdos_getch_ex(int echo)
5312: {
5313: static char prev = 0;
5314:
5315: msdos_stdio_reopen();
5316:
5317: process_t *process = msdos_process_info_get(current_psp);
5318: int fd = msdos_psp_get_file_table(0, current_psp);
5319:
5320: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
5321: // stdin is redirected to file
5322: retry:
5323: char data;
5324: if(msdos_read(fd, &data, 1) == 1) {
5325: char tmp = data;
5326: if(data == 0x0a) {
5327: if(prev == 0x0d) {
5328: goto retry; // CRLF -> skip LF
5329: } else {
5330: data = 0x0d; // LF only -> CR
5331: }
5332: }
5333: prev = tmp;
5334: return(data);
5335: }
5336: return(EOF);
5337: }
5338:
5339: // input from console
5340: int key_char, key_scan;
5341: if(key_recv != 0) {
5342: key_char = (key_code >> 0) & 0xff;
5343: key_scan = (key_code >> 8) & 0xff;
5344: key_code >>= 16;
5345: key_recv >>= 16;
5346: } else {
5347: while(key_buf_char != NULL && key_buf_scan != NULL && !m_exit) {
5348: if(key_buf_char != NULL && key_buf_scan != NULL) {
5349: #ifdef USE_SERVICE_THREAD
5350: EnterCriticalSection(&key_buf_crit_sect);
5351: #endif
5352: bool empty = pcbios_is_key_buffer_empty();
5353: #ifdef USE_SERVICE_THREAD
5354: LeaveCriticalSection(&key_buf_crit_sect);
5355: #endif
5356: if(!empty) break;
5357: }
5358: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
5359: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
5360: if(_kbhit()) {
5361: if(key_buf_char != NULL && key_buf_scan != NULL) {
5362: #ifdef USE_SERVICE_THREAD
5363: EnterCriticalSection(&key_buf_crit_sect);
5364: #endif
5365: pcbios_set_key_buffer(_getch(), 0x00);
5366: #ifdef USE_SERVICE_THREAD
5367: LeaveCriticalSection(&key_buf_crit_sect);
5368: #endif
5369: }
5370: } else {
5371: Sleep(10);
5372: }
5373: } else {
5374: if(!update_key_buffer()) {
5375: Sleep(10);
5376: }
5377: }
5378: }
5379: if(m_exit) {
5380: // insert CR to terminate input loops
5381: key_char = 0x0d;
5382: key_scan = 0;
5383: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
5384: #ifdef USE_SERVICE_THREAD
5385: EnterCriticalSection(&key_buf_crit_sect);
5386: #endif
5387: pcbios_get_key_buffer(&key_char, &key_scan);
5388: #ifdef USE_SERVICE_THREAD
5389: LeaveCriticalSection(&key_buf_crit_sect);
5390: #endif
5391: }
5392: }
5393: if(echo && key_char) {
5394: msdos_putch(key_char);
5395: }
5396: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
5397: }
5398:
5399: inline int msdos_getch()
5400: {
5401: return(msdos_getch_ex(0));
5402: }
5403:
5404: inline int msdos_getche()
5405: {
5406: return(msdos_getch_ex(1));
5407: }
5408:
5409: int msdos_write(int fd, const void *buffer, unsigned int count)
5410: {
5411: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
5412: // write to serial port
5413: int written = 0;
5414: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
5415: UINT8 *buf = (UINT8 *)buffer;
5416: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
5417: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
5418: DWORD timeout = timeGetTime() + 1000;
5419: while(written < count) {
5420: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x20) {
5421: sio_write(file_handler[fd].sio_port - 1, 0, buf[written++]);
5422: timeout = timeGetTime() + 1000;
5423: } else {
5424: if(timeGetTime() > timeout) {
5425: break;
5426: }
5427: Sleep(10);
5428: }
5429: }
5430: sio_write(file_handler[fd].sio_port - 1, 3, selector);
5431: }
5432: return(written);
5433: } else if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].lpt_port >= 1 && file_handler[fd].lpt_port <= 3) {
5434: // write to printer port
5435: UINT8 *buf = (UINT8 *)buffer;
5436: for(unsigned int i = 0; i < count; i++) {
5437: // printer_out(file_handler[fd].lpt_port - 1, buf[i]);
5438: pcbios_printer_out(file_handler[fd].lpt_port - 1, buf[i]);
5439: }
5440: return(count);
5441: } else if(fd == 1 && file_handler[1].valid && !file_handler[1].atty) {
5442: // CR+LF -> LF
5443: static int is_cr = 0;
5444: UINT8 *buf = (UINT8 *)buffer;
5445: for(unsigned int i = 0; i < count; i++) {
5446: UINT8 data = buf[i];
5447: if(is_cr) {
5448: if(data != 0x0a) {
5449: UINT8 tmp = 0x0d;
5450: _write(1, &tmp, 1);
5451: }
5452: _write(1, &data, 1);
5453: is_cr = 0;
5454: } else if(data == 0x0d) {
5455: is_cr = 1;
5456: } else {
5457: _write(1, &data, 1);
5458: }
5459: }
5460: return(count);
5461: }
5462: vram_flush();
5463: return(_write(fd, buffer, count));
5464: }
5465:
5466: void msdos_putch(UINT8 data)
5467: {
5468: msdos_stdio_reopen();
5469:
5470: process_t *process = msdos_process_info_get(current_psp);
5471: int fd = msdos_psp_get_file_table(1, current_psp);
5472:
5473: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
5474: // stdout is redirected to file
5475: msdos_write(fd, &data, 1);
5476: return;
5477: }
5478:
5479: // call int 29h ?
5480: if(*(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) &&
5481: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
5482: // int 29h is not hooked, no need to call int 29h
5483: msdos_putch_fast(data);
5484: #ifdef USE_SERVICE_THREAD
5485: } else if(in_service && main_thread_id != GetCurrentThreadId()) {
5486: // XXX: in usually we should not reach here
5487: // this is called from service thread to echo the input
5488: // we can not call int 29h because it causes a critial issue to control cpu running in main thread :-(
5489: msdos_putch_fast(data);
5490: #endif
5491: } else if(in_service_29h) {
5492: // disallow reentering call int 29h routine to prevent an infinite loop :-(
5493: msdos_putch_fast(data);
5494: } else {
5495: // this is called from main thread, so we can call int 29h :-)
5496: in_service_29h = true;
5497: try {
5498: UINT32 tmp_pc = m_pc;
5499: UINT16 tmp_ax = REG16(AX);
5500: UINT32 tmp_bx = REG16(BX); // BX may be destroyed by some versions of DOS 3.3
5501:
5502: // call int 29h routine is at fffc:0027
5503: i386_call_far(DUMMY_TOP >> 4, 0x0027);
5504: REG8(AL) = data;
5505:
5506: // run cpu until call int 29h routine is done
5507: while(!m_exit && tmp_pc != m_pc) {
5508: try {
5509: hardware_run_cpu();
5510: } catch(...) {
5511: }
5512: }
5513: REG16(AX) = tmp_ax;
5514: REG16(BX) = tmp_bx;
5515: } catch(...) {
5516: }
5517: in_service_29h = false;
5518: }
5519: }
5520:
5521: void msdos_putch_fast(UINT8 data)
5522: #ifdef USE_SERVICE_THREAD
5523: {
5524: EnterCriticalSection(&putch_crit_sect);
5525: msdos_putch_tmp(data);
5526: LeaveCriticalSection(&putch_crit_sect);
5527: }
5528: void msdos_putch_tmp(UINT8 data)
5529: #endif
5530: {
5531: CONSOLE_SCREEN_BUFFER_INFO csbi;
5532: SMALL_RECT rect;
5533: COORD co;
5534: static int p = 0;
5535: static int is_kanji = 0;
5536: static int is_esc = 0;
5537: static int stored_x;
5538: static int stored_y;
5539: static WORD stored_a;
5540: static char tmp[64], out[64];
5541:
5542: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
5543:
5544: // output to console
5545: tmp[p++] = data;
5546:
5547: vram_flush();
5548:
5549: if(is_kanji) {
5550: // kanji character
5551: is_kanji = 0;
5552: } else if(is_esc) {
5553: // escape sequense
5554: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
5555: p = is_esc = 0;
5556: } else if(tmp[1] == '=' && p == 4) {
5557: co.X = tmp[3] - 0x20;
5558: co.Y = tmp[2] - 0x20 + scr_top;
5559: SetConsoleCursorPosition(hStdout, co);
5560: mem[0x450 + mem[0x462] * 2] = co.X;
5561: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
5562: cursor_moved = false;
5563: cursor_moved_by_crtc = false;
5564: p = is_esc = 0;
5565: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
5566: if(cursor_moved_by_crtc) {
5567: if(!restore_console_on_exit) {
5568: GetConsoleScreenBufferInfo(hStdout, &csbi);
5569: scr_top = csbi.srWindow.Top;
5570: }
5571: co.X = mem[0x450 + REG8(BH) * 2];
5572: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
5573: SetConsoleCursorPosition(hStdout, co);
5574: cursor_moved_by_crtc = false;
5575: }
5576: GetConsoleScreenBufferInfo(hStdout, &csbi);
5577: co.X = csbi.dwCursorPosition.X;
5578: co.Y = csbi.dwCursorPosition.Y;
5579: WORD wAttributes = csbi.wAttributes;
5580:
5581: if(tmp[1] == 'D') {
5582: co.Y++;
5583: } else if(tmp[1] == 'E') {
5584: co.X = 0;
5585: co.Y++;
5586: } else if(tmp[1] == 'M') {
5587: co.Y--;
5588: } else if(tmp[1] == '*') {
5589: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5590: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5591: co.X = 0;
5592: co.Y = csbi.srWindow.Top;
5593: } else if(tmp[1] == '[') {
5594: int param[256], params = 0;
5595: memset(param, 0, sizeof(param));
5596: for(int i = 2; i < p; i++) {
5597: if(tmp[i] >= '0' && tmp[i] <= '9') {
5598: param[params] *= 10;
5599: param[params] += tmp[i] - '0';
5600: } else {
5601: params++;
5602: }
5603: }
5604: if(data == 'A') {
5605: co.Y -= (params == 0) ? 1 : param[0];
5606: } else if(data == 'B') {
5607: co.Y += (params == 0) ? 1 : param[0];
5608: } else if(data == 'C') {
5609: co.X += (params == 0) ? 1 : param[0];
5610: } else if(data == 'D') {
5611: co.X -= (params == 0) ? 1 : param[0];
5612: } else if(data == 'H' || data == 'f') {
5613: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
5614: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
5615: } else if(data == 'J') {
5616: clear_scr_buffer(csbi.wAttributes);
5617: if(param[0] == 0) {
5618: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
5619: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5620: if(co.Y < csbi.srWindow.Bottom) {
5621: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5622: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5623: }
5624: } else if(param[0] == 1) {
5625: if(co.Y > csbi.srWindow.Top) {
5626: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
5627: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5628: }
5629: SET_RECT(rect, 0, co.Y, co.X, co.Y);
5630: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5631: } else if(param[0] == 2) {
5632: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5633: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5634: co.X = co.Y = 0;
5635: }
5636: } else if(data == 'K') {
5637: clear_scr_buffer(csbi.wAttributes);
5638: if(param[0] == 0) {
5639: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
5640: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5641: } else if(param[0] == 1) {
5642: SET_RECT(rect, 0, co.Y, co.X, co.Y);
5643: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5644: } else if(param[0] == 2) {
5645: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
5646: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5647: }
5648: } else if(data == 'L') {
5649: if(params == 0) {
5650: param[0] = 1;
5651: }
5652: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5653: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5654: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5655: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5656: clear_scr_buffer(csbi.wAttributes);
5657: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
5658: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5659: co.X = 0;
5660: } else if(data == 'M') {
5661: if(params == 0) {
5662: param[0] = 1;
5663: }
5664: if(co.Y + param[0] > csbi.srWindow.Bottom) {
5665: clear_scr_buffer(csbi.wAttributes);
5666: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5667: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5668: } else {
5669: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5670: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5671: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5672: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5673: clear_scr_buffer(csbi.wAttributes);
5674: }
5675: co.X = 0;
5676: } else if(data == 'h') {
5677: if(tmp[2] == '>' && tmp[3] == '5') {
5678: ci_new.bVisible = FALSE;
5679: }
5680: } else if(data == 'l') {
5681: if(tmp[2] == '>' && tmp[3] == '5') {
5682: ci_new.bVisible = TRUE;
5683: }
5684: } else if(data == 'm') {
5685: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
5686: int reverse = 0, hidden = 0;
5687: for(int i = 0; i < params; i++) {
5688: if(param[i] == 1) {
5689: wAttributes |= FOREGROUND_INTENSITY;
5690: } else if(param[i] == 4) {
5691: wAttributes |= COMMON_LVB_UNDERSCORE;
5692: } else if(param[i] == 7) {
5693: reverse = 1;
5694: } else if(param[i] == 8 || param[i] == 16) {
5695: hidden = 1;
5696: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
5697: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
5698: if(param[i] >= 17 && param[i] <= 23) {
5699: param[i] -= 16;
5700: } else {
5701: param[i] -= 30;
5702: }
5703: if(param[i] & 1) {
5704: wAttributes |= FOREGROUND_RED;
5705: }
5706: if(param[i] & 2) {
5707: wAttributes |= FOREGROUND_GREEN;
5708: }
5709: if(param[i] & 4) {
5710: wAttributes |= FOREGROUND_BLUE;
5711: }
5712: } else if(param[i] >= 40 && param[i] <= 47) {
5713: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
5714: if((param[i] - 40) & 1) {
5715: wAttributes |= BACKGROUND_RED;
5716: }
5717: if((param[i] - 40) & 2) {
5718: wAttributes |= BACKGROUND_GREEN;
5719: }
5720: if((param[i] - 40) & 4) {
5721: wAttributes |= BACKGROUND_BLUE;
5722: }
5723: }
5724: }
5725: if(reverse) {
5726: wAttributes &= ~0xff;
5727: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
5728: }
5729: if(hidden) {
5730: wAttributes &= ~0x0f;
5731: wAttributes |= (wAttributes >> 4) & 0x0f;
5732: }
5733: } else if(data == 'n') {
5734: if(param[0] == 6) {
5735: char tmp[16];
5736: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
5737: int len = strlen(tmp);
5738: if(key_buf_char != NULL && key_buf_scan != NULL) {
5739: #ifdef USE_SERVICE_THREAD
5740: EnterCriticalSection(&key_buf_crit_sect);
5741: #endif
5742: for(int i = 0; i < len; i++) {
5743: pcbios_set_key_buffer(tmp[i], 0x00);
5744: }
5745: #ifdef USE_SERVICE_THREAD
5746: LeaveCriticalSection(&key_buf_crit_sect);
5747: #endif
5748: }
5749: }
5750: } else if(data == 's') {
5751: stored_x = co.X;
5752: stored_y = co.Y;
5753: stored_a = wAttributes;
5754: } else if(data == 'u') {
5755: co.X = stored_x;
5756: co.Y = stored_y;
5757: wAttributes = stored_a;
5758: }
5759: }
5760: if(co.X < 0) {
5761: co.X = 0;
5762: } else if(co.X >= csbi.dwSize.X) {
5763: co.X = csbi.dwSize.X - 1;
5764: }
5765: if(co.Y < csbi.srWindow.Top) {
5766: co.Y = csbi.srWindow.Top;
5767: } else if(co.Y > csbi.srWindow.Bottom) {
5768: co.Y = csbi.srWindow.Bottom;
5769: }
5770: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
5771: SetConsoleCursorPosition(hStdout, co);
5772: mem[0x450 + mem[0x462] * 2] = co.X;
5773: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
5774: cursor_moved = false;
5775: }
5776: if(wAttributes != csbi.wAttributes) {
5777: SetConsoleTextAttribute(hStdout, wAttributes);
5778: }
5779: p = is_esc = 0;
5780: }
5781: return;
5782: } else {
5783: if(msdos_lead_byte_check(data)) {
5784: is_kanji = 1;
5785: return;
5786: } else if(data == 0x1b) {
5787: is_esc = 1;
5788: return;
5789: }
5790: }
5791:
5792: DWORD q = 0, num;
5793: is_kanji = 0;
5794: for(int i = 0; i < p; i++) {
5795: UINT8 c = tmp[i];
5796: if(is_kanji) {
5797: is_kanji = 0;
5798: } else if(msdos_lead_byte_check(data)) {
5799: is_kanji = 1;
5800: } else if(msdos_ctrl_code_check(data)) {
5801: out[q++] = '^';
5802: c += 'A' - 1;
5803: }
5804: out[q++] = c;
5805: }
5806: if(cursor_moved_by_crtc) {
5807: if(!restore_console_on_exit) {
5808: GetConsoleScreenBufferInfo(hStdout, &csbi);
5809: scr_top = csbi.srWindow.Top;
5810: }
5811: co.X = mem[0x450 + REG8(BH) * 2];
5812: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
5813: SetConsoleCursorPosition(hStdout, co);
5814: cursor_moved_by_crtc = false;
5815: }
5816: if(q == 1 && out[0] == 0x08) {
5817: // back space
5818: GetConsoleScreenBufferInfo(hStdout, &csbi);
5819: if(csbi.dwCursorPosition.X > 0) {
5820: co.X = csbi.dwCursorPosition.X - 1;
5821: co.Y = csbi.dwCursorPosition.Y;
5822: SetConsoleCursorPosition(hStdout, co);
5823: } else if(csbi.dwCursorPosition.Y > 0) {
5824: co.X = csbi.dwSize.X - 1;
5825: co.Y = csbi.dwCursorPosition.Y - 1;
5826: SetConsoleCursorPosition(hStdout, co);
5827: } else {
5828: WriteConsoleA(hStdout, out, q, &num, NULL); // to make sure
5829: }
5830: } else {
5831: WriteConsoleA(hStdout, out, q, &num, NULL);
5832: }
5833: p = 0;
5834:
5835: if(!restore_console_on_exit) {
5836: GetConsoleScreenBufferInfo(hStdout, &csbi);
5837: scr_top = csbi.srWindow.Top;
5838: }
5839: cursor_moved = true;
5840: }
5841:
5842: int msdos_aux_in()
5843: {
5844: msdos_stdio_reopen();
5845:
5846: process_t *process = msdos_process_info_get(current_psp);
5847: int fd = msdos_psp_get_file_table(3, current_psp);
5848:
5849: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
5850: char data = 0;
5851: msdos_read(fd, &data, 1);
5852: return(data);
5853: } else {
5854: return(EOF);
5855: }
5856: }
5857:
5858: void msdos_aux_out(char data)
5859: {
5860: msdos_stdio_reopen();
5861:
5862: process_t *process = msdos_process_info_get(current_psp);
5863: int fd = msdos_psp_get_file_table(3, current_psp);
5864:
5865: if(fd < process->max_files && file_handler[fd].valid) {
5866: msdos_write(fd, &data, 1);
5867: }
5868: }
5869:
5870: void msdos_prn_out(char data)
5871: {
5872: msdos_stdio_reopen();
5873:
5874: process_t *process = msdos_process_info_get(current_psp);
5875: int fd = msdos_psp_get_file_table(4, current_psp);
5876:
5877: if(fd < process->max_files && file_handler[fd].valid) {
5878: msdos_write(fd, &data, 1);
5879: }
5880: }
5881:
5882: // memory control
5883:
5884: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs, const char *prog_name = NULL)
5885: {
5886: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5887:
5888: mcb->mz = mz;
5889: mcb->psp = psp;
5890: mcb->paragraphs = paragraphs;
5891:
5892: if(prog_name != NULL) {
5893: memset(mcb->prog_name, 0, 8);
5894: memcpy(mcb->prog_name, prog_name, min(8, strlen(prog_name)));
5895: }
5896: return(mcb);
5897: }
5898:
5899: void msdos_mcb_check(mcb_t *mcb)
5900: {
5901: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
5902: #if 0
5903: // shutdown now !!!
5904: fatalerror("broken memory control block\n");
5905: #else
5906: // return error code and continue
5907: throw(0x07); // broken memory control block
5908: #endif
5909: }
5910: }
5911:
5912: void msdos_mem_split(int seg, int paragraphs)
5913: {
5914: int mcb_seg = seg - 1;
5915: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5916: msdos_mcb_check(mcb);
5917:
5918: if(mcb->paragraphs > paragraphs) {
5919: int new_seg = mcb_seg + 1 + paragraphs;
5920: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
5921:
5922: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5923: mcb->mz = 'M';
5924: mcb->paragraphs = paragraphs;
5925: }
5926: }
5927:
5928: void msdos_mem_merge(int seg)
5929: {
5930: int mcb_seg = seg - 1;
5931: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5932: msdos_mcb_check(mcb);
5933:
5934: while(1) {
5935: if(mcb->mz == 'Z') {
5936: break;
5937: }
5938: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5939: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5940: msdos_mcb_check(next_mcb);
5941:
5942: if(next_mcb->psp != 0) {
5943: break;
5944: }
5945: mcb->mz = next_mcb->mz;
5946: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
5947: }
5948: }
5949:
5950: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
5951: {
5952: while(1) {
5953: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5954: bool last_block;
5955:
5956: if(mcb->psp == 0) {
5957: msdos_mem_merge(mcb_seg + 1);
5958: } else {
5959: msdos_mcb_check(mcb);
5960: }
5961: if(!(last_block = (mcb->mz == 'Z'))) {
5962: // check if the next is dummy mcb to link to umb
5963: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5964: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5965: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5966: }
5967: if(!(new_process && !last_block)) {
5968: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
5969: msdos_mem_split(mcb_seg + 1, paragraphs);
5970: mcb->psp = current_psp;
5971: return(mcb_seg + 1);
5972: }
5973: }
5974: if(mcb->mz == 'Z') {
5975: break;
5976: }
5977: mcb_seg += 1 + mcb->paragraphs;
5978: }
5979: return(-1);
5980: }
5981:
5982: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5983: {
5984: int mcb_seg = seg - 1;
5985: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5986: msdos_mcb_check(mcb);
5987: int current_paragraphs = mcb->paragraphs;
5988:
5989: msdos_mem_merge(seg);
5990: if(paragraphs > mcb->paragraphs) {
5991: if(max_paragraphs) {
5992: *max_paragraphs = mcb->paragraphs;
5993: }
5994: msdos_mem_split(seg, current_paragraphs);
5995: return(-1);
5996: }
5997: msdos_mem_split(seg, paragraphs);
5998: return(0);
5999: }
6000:
6001: void msdos_mem_free(int seg)
6002: {
6003: int mcb_seg = seg - 1;
6004: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6005: msdos_mcb_check(mcb);
6006:
6007: mcb->psp = 0;
6008: msdos_mem_merge(seg);
6009: }
6010:
6011: int msdos_mem_get_free(int mcb_seg, int new_process)
6012: {
6013: int max_paragraphs = 0;
6014:
6015: while(1) {
6016: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6017: bool last_block;
6018:
6019: msdos_mcb_check(mcb);
6020:
6021: if(!(last_block = (mcb->mz == 'Z'))) {
6022: // check if the next is dummy mcb to link to umb
6023: int next_seg = mcb_seg + 1 + mcb->paragraphs;
6024: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
6025: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
6026: }
6027: if(!(new_process && !last_block)) {
6028: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
6029: max_paragraphs = mcb->paragraphs;
6030: }
6031: }
6032: if(mcb->mz == 'Z') {
6033: break;
6034: }
6035: mcb_seg += 1 + mcb->paragraphs;
6036: }
6037: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
6038: }
6039:
6040: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
6041: {
6042: int last_seg = -1;
6043:
6044: while(1) {
6045: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6046: msdos_mcb_check(mcb);
6047:
6048: if(mcb->psp == psp) {
6049: last_seg = mcb_seg;
6050: }
6051: if(mcb->mz == 'Z') {
6052: break;
6053: }
6054: mcb_seg += 1 + mcb->paragraphs;
6055: }
6056: return(last_seg);
6057: }
6058:
6059: int msdos_mem_get_umb_linked()
6060: {
6061: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
6062: msdos_mcb_check(mcb);
6063:
6064: if(mcb->mz == 'M') {
6065: return(-1);
6066: }
6067: return(0);
6068: }
6069:
6070: void msdos_mem_link_umb()
6071: {
6072: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
6073: msdos_mcb_check(mcb);
6074:
6075: mcb->mz = 'M';
6076: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
6077:
6078: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
6079: }
6080:
6081: void msdos_mem_unlink_umb()
6082: {
6083: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
6084: msdos_mcb_check(mcb);
6085:
6086: mcb->mz = 'Z';
6087: mcb->paragraphs = 0;
6088:
6089: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
6090: }
6091:
6092: #ifdef SUPPORT_HMA
6093:
6094: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
6095: {
6096: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
6097:
6098: mcb->ms[0] = 'M';
6099: mcb->ms[1] = 'S';
6100: mcb->owner = owner;
6101: mcb->size = size;
6102: mcb->next = next;
6103: return(mcb);
6104: }
6105:
6106: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
6107: {
6108: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
6109: }
6110:
6111: int msdos_hma_mem_split(int offset, int size)
6112: {
6113: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
6114:
6115: if(!msdos_is_hma_mcb_valid(mcb)) {
6116: return(-1);
6117: }
6118: if(mcb->size >= size + 0x10) {
6119: int new_offset = offset + 0x10 + size;
6120: int new_size = mcb->size - 0x10 - size;
6121:
6122: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
6123: mcb->size = size;
6124: mcb->next = new_offset;
6125: return(0);
6126: }
6127: return(-1);
6128: }
6129:
6130: void msdos_hma_mem_merge(int offset)
6131: {
6132: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
6133:
6134: if(!msdos_is_hma_mcb_valid(mcb)) {
6135: return;
6136: }
6137: while(1) {
6138: if(mcb->next == 0) {
6139: break;
6140: }
6141: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
6142:
6143: if(!msdos_is_hma_mcb_valid(next_mcb)) {
6144: return;
6145: }
6146: if(next_mcb->owner != 0) {
6147: break;
6148: }
6149: mcb->size += 0x10 + next_mcb->size;
6150: mcb->next = next_mcb->next;
6151: }
6152: }
6153:
6154: int msdos_hma_mem_alloc(int size, UINT16 owner)
6155: {
6156: int offset = 0x10; // first mcb in HMA
6157:
6158: while(1) {
6159: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
6160:
6161: if(!msdos_is_hma_mcb_valid(mcb)) {
6162: return(-1);
6163: }
6164: if(mcb->owner == 0) {
6165: msdos_hma_mem_merge(offset);
6166: }
6167: if(mcb->owner == 0 && mcb->size >= size) {
6168: msdos_hma_mem_split(offset, size);
6169: mcb->owner = owner;
6170: return(offset);
6171: }
6172: if(mcb->next == 0) {
6173: break;
6174: }
6175: offset = mcb->next;
6176: }
6177: return(-1);
6178: }
6179:
6180: int msdos_hma_mem_realloc(int offset, int size)
6181: {
6182: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
6183:
6184: if(!msdos_is_hma_mcb_valid(mcb)) {
6185: return(-1);
6186: }
6187: if(mcb->size < size) {
6188: return(-1);
6189: }
6190: msdos_hma_mem_split(offset, size);
6191: return(0);
6192: }
6193:
6194: void msdos_hma_mem_free(int offset)
6195: {
6196: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
6197:
6198: if(!msdos_is_hma_mcb_valid(mcb)) {
6199: return;
6200: }
6201: mcb->owner = 0;
6202: msdos_hma_mem_merge(offset);
6203: }
6204:
6205: int msdos_hma_mem_get_free(int *available_offset)
6206: {
6207: int offset = 0x10; // first mcb in HMA
6208: int size = 0;
6209:
6210: while(1) {
6211: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
6212:
6213: if(!msdos_is_hma_mcb_valid(mcb)) {
6214: return(0);
6215: }
6216: if(mcb->owner == 0 && size < mcb->size) {
6217: if(available_offset != NULL) {
6218: *available_offset = offset;
6219: }
6220: size = mcb->size;
6221: }
6222: if(mcb->next == 0) {
6223: break;
6224: }
6225: offset = mcb->next;
6226: }
6227: return(size);
6228: }
6229:
6230: #endif
6231:
6232: // environment
6233:
6234: void msdos_env_set_argv(int env_seg, const char *argv)
6235: {
6236: char *dst = (char *)(mem + (env_seg << 4));
6237:
6238: while(1) {
6239: if(dst[0] == 0) {
6240: break;
6241: }
6242: dst += strlen(dst) + 1;
6243: }
6244: *dst++ = 0; // end of environment
6245: *dst++ = 1; // top of argv[0]
6246: *dst++ = 0;
6247: memcpy(dst, argv, strlen(argv));
6248: dst += strlen(argv);
6249: *dst++ = 0;
6250: *dst++ = 0;
6251: }
6252:
6253: const char *msdos_env_get_argv(int env_seg)
6254: {
6255: static char env[ENV_SIZE];
6256: char *src = env;
6257:
6258: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
6259: while(1) {
6260: if(src[0] == 0) {
6261: if(src[1] == 1) {
6262: return(src + 3);
6263: }
6264: break;
6265: }
6266: src += strlen(src) + 1;
6267: }
6268: return(NULL);
6269: }
6270:
6271: const char *msdos_env_get(int env_seg, const char *name)
6272: {
6273: static char env[ENV_SIZE];
6274: char *src = env;
6275:
6276: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
6277: while(1) {
6278: if(src[0] == 0) {
6279: break;
6280: }
6281: int len = strlen(src);
6282: char *n = my_strtok(src, "=");
6283: char *v = src + strlen(n) + 1;
6284:
6285: if(_stricmp(name, n) == 0) {
6286: return(v);
6287: }
6288: src += len + 1;
6289: }
6290: return(NULL);
6291: }
6292:
6293: void msdos_env_set(int env_seg, const char *name, const char *value)
6294: {
6295: char env[ENV_SIZE];
6296: char *src = env;
6297: char *dst = (char *)(mem + (env_seg << 4));
6298: const char *argv = msdos_env_get_argv(env_seg);
6299: int done = 0;
6300:
6301: memcpy(src, dst, ENV_SIZE);
6302: memset(dst, 0, ENV_SIZE);
6303: while(1) {
6304: if(src[0] == 0) {
6305: break;
6306: }
6307: int len = strlen(src);
6308: char *n = my_strtok(src, "=");
6309: char *v = src + strlen(n) + 1;
6310: char tmp[1024];
6311:
6312: if(_stricmp(name, n) == 0) {
6313: sprintf(tmp, "%s=%s", n, value);
6314: done = 1;
6315: } else {
6316: sprintf(tmp, "%s=%s", n, v);
6317: }
6318: memcpy(dst, tmp, strlen(tmp));
6319: dst += strlen(tmp) + 1;
6320: src += len + 1;
6321: }
6322: if(!done) {
6323: char tmp[1024];
6324:
6325: sprintf(tmp, "%s=%s", name, value);
6326: memcpy(dst, tmp, strlen(tmp));
6327: dst += strlen(tmp) + 1;
6328: }
6329: if(argv) {
6330: *dst++ = 0; // end of environment
6331: *dst++ = 1; // top of argv[0]
6332: *dst++ = 0;
6333: memcpy(dst, argv, strlen(argv));
6334: dst += strlen(argv);
6335: *dst++ = 0;
6336: *dst++ = 0;
6337: }
6338: }
6339:
6340: // process
6341:
6342: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
6343: {
6344: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6345:
6346: memset(psp, 0, PSP_SIZE);
6347: psp->exit[0] = 0xcd;
6348: psp->exit[1] = 0x20;
6349: psp->first_mcb = mcb_seg;
6350: #if 1
6351: psp->call5[0] = 0xcd; // int 30h
6352: psp->call5[1] = 0x30;
6353: psp->call5[2] = 0xc3; // ret
6354: #else
6355: psp->call5[0] = 0x8a; // mov ah, cl
6356: psp->call5[1] = 0xe1;
6357: psp->call5[2] = 0xcd; // int 21h
6358: psp->call5[3] = 0x21;
6359: psp->call5[4] = 0xc3; // ret
6360: #endif
6361: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6362: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6363: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6364: psp->parent_psp = parent_psp;
6365: if(parent_psp == (UINT16)-1) {
6366: for(int i = 0; i < 20; i++) {
6367: if(file_handler[i].valid) {
6368: psp->file_table[i] = i;
6369: } else {
6370: psp->file_table[i] = 0xff;
6371: }
6372: }
6373: } else {
6374: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
6375: }
6376: psp->env_seg = env_seg;
6377: psp->stack.w.l = REG16(SP);
6378: psp->stack.w.h = SREG(SS);
6379: psp->file_table_size = 20;
6380: psp->file_table_ptr.w.l = 0x18;
6381: psp->file_table_ptr.w.h = psp_seg;
6382: psp->service[0] = 0xcd;
6383: psp->service[1] = 0x21;
6384: psp->service[2] = 0xcb;
6385: return(psp);
6386: }
6387:
6388: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
6389: {
6390: if(psp_seg && fd < 20) {
6391: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6392: psp->file_table[fd] = value;
6393: }
6394: }
6395:
6396: int msdos_psp_get_file_table(int fd, int psp_seg)
6397: {
6398: if(psp_seg && fd < 20) {
6399: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6400: fd = psp->file_table[fd];
6401: }
6402: return fd;
6403: }
6404:
6405: int msdos_process_exec(const char *cmd, param_block_t *param, UINT8 al, bool first_process = false)
6406: {
6407: // load command file
6408: int fd = -1;
6409: int sio_port = 0;
6410: int lpt_port = 0;
6411: int dos_command = 0;
6412: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
6413: char pipe_stdin_path[MAX_PATH] = {0};
6414: char pipe_stdout_path[MAX_PATH] = {0};
6415: char pipe_stderr_path[MAX_PATH] = {0};
6416:
6417: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
6418: int opt_len = mem[opt_ofs];
6419: memset(opt, 0, sizeof(opt));
6420: memcpy(opt, mem + opt_ofs + 1, opt_len);
6421:
6422: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
6423: // this is a batch file, run command.com
6424: char tmp[MAX_PATH];
6425: if(opt_len != 0) {
6426: sprintf(tmp, "/C %s %s", cmd, opt);
6427: } else {
6428: sprintf(tmp, "/C %s", cmd);
6429: }
6430: strcpy(opt, tmp);
6431: opt_len = strlen(opt);
6432: mem[opt_ofs] = opt_len;
6433: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6434: strcpy(command, comspec_path);
6435: strcpy(name_tmp, "COMMAND.COM");
6436: } else {
6437: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
6438: // redirect C:\COMMAND.COM to comspec_path
6439: strcpy(command, comspec_path);
6440: } else {
6441: strcpy(command, cmd);
6442: }
6443: if(GetFullPathNameA(command, MAX_PATH, path, &name) == 0) {
6444: return(-1);
6445: }
6446: memset(name_tmp, 0, sizeof(name_tmp));
6447: strcpy(name_tmp, name);
6448:
6449: // check command.com
6450: if((_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) && _access(comspec_path, 0) != 0) {
6451: // we can not load command.com, so run program directly if "command /c (program)" is specified
6452: if(opt_len == 0) {
6453: // process_t *current_process = msdos_process_info_get(current_psp);
6454: process_t *current_process = NULL;
6455: for(int i = 0; i < MAX_PROCESS; i++) {
6456: if(process[i].psp == current_psp) {
6457: current_process = &process[i];
6458: break;
6459: }
6460: }
6461: if(current_process != NULL) {
6462: param->cmd_line.dw = current_process->dta.dw;
6463: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
6464: opt_len = mem[opt_ofs];
6465: memset(opt, 0, sizeof(opt));
6466: memcpy(opt, mem + opt_ofs + 1, opt_len);
6467: }
6468: }
6469: for(int i = 0; i < opt_len; i++) {
6470: if(opt[i] == ' ') {
6471: continue;
6472: }
6473: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
6474: for(int j = i + 3; j < opt_len; j++) {
6475: if(opt[j] == ' ') {
6476: continue;
6477: }
6478: char *token = my_strtok(opt + j, " ");
6479:
6480: strcpy(command, token);
6481: char tmp[MAX_PATH];
6482: strcpy(tmp, token + strlen(token) + 1);
6483: strcpy(opt, "");
6484: for(int i = 0; i < strlen(tmp); i++) {
6485: if(tmp[i] != ' ') {
6486: strcpy(opt, tmp + i);
6487: break;
6488: }
6489: }
6490: strcpy(tmp, opt);
6491:
6492: if(al == 0x00) {
6493: #define GET_FILE_PATH() { \
6494: if(token[0] != '>' && token[0] != '<') { \
6495: token++; \
6496: } \
6497: token++; \
6498: while(*token == ' ') { \
6499: token++; \
6500: } \
6501: char *ptr = token; \
6502: while(*ptr != ' ' && *ptr != '\r' && *ptr != '\0') { \
6503: ptr++; \
6504: } \
6505: *ptr = '\0'; \
6506: }
6507: if((token = strstr(opt, "0<")) != NULL || (token = strstr(opt, "<")) != NULL) {
6508: GET_FILE_PATH();
6509: strcpy(pipe_stdin_path, token);
6510: strcpy(opt, tmp);
6511: }
6512: if((token = strstr(opt, "1>")) != NULL || (token = strstr(opt, ">")) != NULL) {
6513: GET_FILE_PATH();
6514: strcpy(pipe_stdout_path, token);
6515: strcpy(opt, tmp);
6516: }
6517: if((token = strstr(opt, "2>")) != NULL) {
6518: GET_FILE_PATH();
6519: strcpy(pipe_stderr_path, token);
6520: strcpy(opt, tmp);
6521: }
6522: #undef GET_FILE_PATH
6523:
6524: if((token = strstr(opt, "0<")) != NULL) {
6525: *token = '\0';
6526: }
6527: if((token = strstr(opt, "1>")) != NULL) {
6528: *token = '\0';
6529: }
6530: if((token = strstr(opt, "2>")) != NULL) {
6531: *token = '\0';
6532: }
6533: if((token = strstr(opt, "<")) != NULL) {
6534: *token = '\0';
6535: }
6536: if((token = strstr(opt, ">")) != NULL) {
6537: *token = '\0';
6538: }
6539: }
6540: for(int i = strlen(opt) - 1; i >= 0 && opt[i] == ' '; i--) {
6541: opt[i] = '\0';
6542: }
6543: opt_len = strlen(opt);
6544: mem[opt_ofs] = opt_len;
6545: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6546: dos_command = 1;
6547: break;
6548: }
6549: }
6550: break;
6551: }
6552: }
6553: }
6554:
6555: // load command file
6556: strcpy(path, command);
6557: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
6558: sprintf(path, "%s.COM", command);
6559: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
6560: sprintf(path, "%s.EXE", command);
6561: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
6562: sprintf(path, "%s.BAT", command);
6563: if(_access(path, 0) == 0) {
6564: // this is a batch file, run command.com
6565: char tmp[MAX_PATH];
6566: if(opt_len != 0) {
6567: sprintf(tmp, "/C %s %s", path, opt);
6568: } else {
6569: sprintf(tmp, "/C %s", path);
6570: }
6571: strcpy(opt, tmp);
6572: opt_len = strlen(opt);
6573: mem[opt_ofs] = opt_len;
6574: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6575: strcpy(path, comspec_path);
6576: strcpy(name_tmp, "COMMAND.COM");
6577: fd = _open(path, _O_RDONLY | _O_BINARY);
6578: } else {
6579: // search path in parent environments
6580: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
6581: const char *env = msdos_env_get(parent_psp->env_seg, "PATH");
6582: if(env != NULL) {
6583: char env_path[4096];
6584: strcpy(env_path, env);
6585: char *token = my_strtok(env_path, ";");
6586:
6587: while(token != NULL) {
6588: if(strlen(token) != 0) {
6589: sprintf(path, "%s", msdos_combine_path(token, command));
6590: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6591: break;
6592: }
6593: sprintf(path, "%s.COM", msdos_combine_path(token, command));
6594: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6595: break;
6596: }
6597: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
6598: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6599: break;
6600: }
6601: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
6602: if(_access(path, 0) == 0) {
6603: // this is a batch file, run command.com
6604: char tmp[MAX_PATH];
6605: if(opt_len != 0) {
6606: sprintf(tmp, "/C %s %s", path, opt);
6607: } else {
6608: sprintf(tmp, "/C %s", path);
6609: }
6610: strcpy(opt, tmp);
6611: opt_len = strlen(opt);
6612: mem[opt_ofs] = opt_len;
6613: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6614: strcpy(path, comspec_path);
6615: strcpy(name_tmp, "COMMAND.COM");
6616: fd = _open(path, _O_RDONLY | _O_BINARY);
6617: break;
6618: }
6619: }
6620: token = my_strtok(NULL, ";");
6621: }
6622: }
6623: }
6624: }
6625: }
6626: }
6627: if(fd == -1) {
6628: // we can not find command.com in the path, so open comspec_path
6629: if(_stricmp(command, "COMMAND.COM") == 0 || _stricmp(command, "COMMAND") == 0) {
6630: strcpy(command, comspec_path);
6631: strcpy(path, command);
6632: fd = _open(path, _O_RDONLY | _O_BINARY);
6633: }
6634: }
6635: if(fd == -1) {
6636: if(!first_process && al == 0 && dos_command) {
6637: // may be dos command
6638: char tmp[MAX_PATH];
6639: if(opt_len != 0) {
6640: sprintf(tmp, "%s %s", command, opt);
6641: } else {
6642: sprintf(tmp, "%s", command);
6643: }
6644: retval = system(tmp);
6645: return(0);
6646: } else {
6647: return(-1);
6648: }
6649: }
6650: memset(file_buffer, 0, sizeof(file_buffer));
6651: _read(fd, file_buffer, sizeof(file_buffer));
6652: _close(fd);
6653:
6654: // check if this is win32 program
6655: if(!first_process && al == 0) {
6656: UINT16 sign_dos = *(UINT16 *)(file_buffer + 0x00);
6657: UINT32 e_lfanew = *(UINT32 *)(file_buffer + 0x3c);
6658: if(sign_dos == IMAGE_DOS_SIGNATURE && e_lfanew >= 0x40 && e_lfanew < 0x400) {
6659: UINT32 sign_nt = *(UINT32 *)(file_buffer + e_lfanew + 0x00);
6660: UINT16 machine = *(UINT16 *)(file_buffer + e_lfanew + 0x04);
6661: if(sign_nt == IMAGE_NT_SIGNATURE && (machine == IMAGE_FILE_MACHINE_I386 || machine == IMAGE_FILE_MACHINE_AMD64)) {
6662: char tmp[MAX_PATH];
6663: if(opt_len != 0) {
6664: sprintf(tmp, "\"%s\" %s", path, opt);
6665: } else {
6666: sprintf(tmp, "\"%s\"", path);
6667: }
6668: retval = system(tmp);
6669: return(0);
6670: }
6671: }
6672: }
6673:
6674: // copy environment
6675: int umb_linked, env_seg, psp_seg;
6676:
6677: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6678: msdos_mem_unlink_umb();
6679: }
6680: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
6681: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
6682: if(umb_linked != 0) {
6683: msdos_mem_link_umb();
6684: }
6685: return(-1);
6686: }
6687: }
6688: if(param->env_seg == 0) {
6689: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
6690: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
6691: } else {
6692: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
6693: }
6694: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
6695:
6696: // check exe header
6697: exe_header_t *header = (exe_header_t *)file_buffer;
6698: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
6699: UINT16 cs, ss, ip, sp;
6700:
6701: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6702: // memory allocation
6703: int header_size = header->header_size * 16;
6704: int load_size = header->pages * 512 - header_size;
6705: if(header_size + load_size < 512) {
6706: load_size = 512 - header_size;
6707: }
6708: paragraphs = (PSP_SIZE + load_size) >> 4;
6709: if(paragraphs + header->min_alloc > free_paragraphs) {
6710: msdos_mem_free(env_seg);
6711: return(-1);
6712: }
6713: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
6714: if(paragraphs > free_paragraphs) {
6715: paragraphs = free_paragraphs;
6716: }
6717: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
6718: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6719: if(umb_linked != 0) {
6720: msdos_mem_link_umb();
6721: }
6722: msdos_mem_free(env_seg);
6723: return(-1);
6724: }
6725: }
6726: // relocation
6727: int start_seg = psp_seg + (PSP_SIZE >> 4);
6728: for(int i = 0; i < header->relocations; i++) {
6729: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6730: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6731: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6732: }
6733: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
6734: // segments
6735: cs = header->init_cs + start_seg;
6736: ss = header->init_ss + start_seg;
6737: ip = header->init_ip;
6738: sp = header->init_sp - 2; // for symdeb
6739: } else {
6740: // memory allocation
6741: paragraphs = free_paragraphs;
6742: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
6743: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6744: if(umb_linked != 0) {
6745: msdos_mem_link_umb();
6746: }
6747: msdos_mem_free(env_seg);
6748: return(-1);
6749: }
6750: }
6751: int start_seg = psp_seg + (PSP_SIZE >> 4);
6752: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
6753: // segments
6754: cs = ss = psp_seg;
6755: ip = 0x100;
6756: sp = 0xfffe;
6757: }
6758: if(umb_linked != 0) {
6759: msdos_mem_link_umb();
6760: }
6761:
6762: // create psp
6763: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
6764: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
6765: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
6766: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
6767: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
6768: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
6769:
6770: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
6771: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
6772: mcb_psp->psp = mcb_env->psp = psp_seg;
6773:
6774: for(int i = 0; i < 8; i++) {
6775: if(name_tmp[i] == '.') {
6776: mcb_psp->prog_name[i] = '\0';
6777: break;
6778: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
6779: mcb_psp->prog_name[i] = name_tmp[i];
6780: i++;
6781: mcb_psp->prog_name[i] = name_tmp[i];
6782: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
6783: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
6784: } else {
6785: mcb_psp->prog_name[i] = name_tmp[i];
6786: }
6787: }
6788:
6789: // process info
6790: process_t *process = msdos_process_info_create(psp_seg);
6791: strcpy(process->module_dir, msdos_short_full_dir(path));
6792: #ifdef USE_DEBUGGER
6793: strcpy(process->module_path, path);
6794: #endif
6795: process->dta.w.l = 0x80;
6796: process->dta.w.h = psp_seg;
6797: process->switchar = '/';
6798: process->max_files = 20;
6799: process->parent_int_10h_feh_called = int_10h_feh_called;
6800: process->parent_int_10h_ffh_called = int_10h_ffh_called;
6801: process->parent_ds = SREG(DS);
6802: process->parent_es = SREG(ES);
6803:
6804: current_psp = psp_seg;
6805: msdos_sda_update(current_psp);
6806:
6807: if(al == 0x00) {
6808: int_10h_feh_called = int_10h_ffh_called = false;
6809:
6810: // pipe
6811: if(pipe_stdin_path[0] != '\0') {
6812: // if((fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY)) != -1) {
6813: if(msdos_is_device_path(pipe_stdin_path)) {
6814: fd = msdos_open_device(pipe_stdin_path, _O_RDONLY | _O_BINARY, &sio_port, &lpt_port);
6815: } else {
6816: fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY);
6817: }
6818: if(fd != -1) {
6819: msdos_file_handler_open(fd, pipe_stdin_path, _isatty(fd), 0, msdos_device_info(pipe_stdin_path), current_psp, sio_port, lpt_port);
6820: psp->file_table[0] = fd;
6821: msdos_psp_set_file_table(fd, fd, current_psp);
6822: }
6823: }
6824: if(pipe_stdout_path[0] != '\0') {
6825: if(_access(pipe_stdout_path, 0) == 0) {
6826: SetFileAttributesA(pipe_stdout_path, FILE_ATTRIBUTE_NORMAL);
6827: DeleteFileA(pipe_stdout_path);
6828: }
6829: // if((fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) {
6830: if(msdos_is_device_path(pipe_stdout_path)) {
6831: fd = msdos_open_device(pipe_stdout_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
6832: } else {
6833: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6834: }
6835: if(fd != -1) {
6836: msdos_file_handler_open(fd, pipe_stdout_path, _isatty(fd), 1, msdos_device_info(pipe_stdout_path), current_psp, sio_port, lpt_port);
6837: psp->file_table[1] = fd;
6838: msdos_psp_set_file_table(fd, fd, current_psp);
6839: }
6840: }
6841: if(pipe_stderr_path[0] != '\0') {
6842: if(_access(pipe_stderr_path, 0) == 0) {
6843: SetFileAttributesA(pipe_stderr_path, FILE_ATTRIBUTE_NORMAL);
6844: DeleteFileA(pipe_stderr_path);
6845: }
6846: // if((fd = _open(pipe_stderr_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) {
6847: if(msdos_is_device_path(pipe_stderr_path)) {
6848: fd = msdos_open_device(pipe_stderr_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
6849: } else {
6850: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6851: }
6852: if(fd != -1) {
6853: msdos_file_handler_open(fd, pipe_stderr_path, _isatty(fd), 1, msdos_device_info(pipe_stderr_path), current_psp, sio_port, lpt_port);
6854: psp->file_table[2] = fd;
6855: msdos_psp_set_file_table(fd, fd, current_psp);
6856: }
6857: }
6858:
6859: // registers and segments
6860: REG16(AX) = REG16(BX) = 0x00;
6861: REG16(CX) = 0xff;
6862: REG16(DX) = psp_seg;
6863: REG16(SI) = ip;
6864: REG16(DI) = sp;
6865: REG16(SP) = sp;
6866: SREG(DS) = SREG(ES) = psp_seg;
6867: SREG(SS) = ss;
6868: i386_load_segment_descriptor(DS);
6869: i386_load_segment_descriptor(ES);
6870: i386_load_segment_descriptor(SS);
6871:
6872: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
6873: i386_jmp_far(cs, ip);
6874: } else if(al == 0x01) {
6875: // copy ss:sp and cs:ip to param block
6876: param->sp = sp;
6877: param->ss = ss;
6878: param->ip = ip;
6879: param->cs = cs;
6880:
6881: // the AX value to be passed to the child program is put on top of the child's stack
6882: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
6883: }
6884: return(0);
6885: }
6886:
6887: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
6888: {
6889: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6890:
6891: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
6892: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
6893: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
6894:
6895: SREG(SS) = psp->stack.w.h;
6896: i386_load_segment_descriptor(SS);
6897: REG16(SP) = psp->stack.w.l;
6898: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
6899:
6900: // process_t *current_process = msdos_process_info_get(psp_seg);
6901: process_t *current_process = NULL;
6902: for(int i = 0; i < MAX_PROCESS; i++) {
6903: if(process[i].psp == psp_seg) {
6904: current_process = &process[i];
6905: break;
6906: }
6907: }
6908: if(current_process == NULL) {
6909: throw(0x1f); // general failure
6910: }
6911: int_10h_feh_called = current_process->parent_int_10h_feh_called;
6912: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
6913: if(current_process->called_by_int2eh) {
6914: REG16(AX) = ret;
6915: }
6916: SREG(DS) = current_process->parent_ds;
6917: SREG(ES) = current_process->parent_es;
6918: i386_load_segment_descriptor(DS);
6919: i386_load_segment_descriptor(ES);
6920:
6921: if(mem_free) {
6922: int mcb_seg;
6923: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
6924: msdos_mem_free(mcb_seg + 1);
6925: }
6926: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
6927: msdos_mem_free(mcb_seg + 1);
6928: }
6929:
6930: for(int i = 0; i < MAX_FILES; i++) {
6931: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
6932: _close(i);
6933: msdos_file_handler_close(i);
6934: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
6935: }
6936: }
6937: msdos_dta_info_free(psp_seg);
6938: }
6939: msdos_stdio_reopen();
6940:
6941: memset(current_process, 0, sizeof(process_t));
6942:
6943: current_psp = psp->parent_psp;
6944: retval = ret;
6945: msdos_sda_update(current_psp);
6946: }
6947:
6948: // drive
6949:
6950: int pcbios_update_drive_param(int drive_num, int force_update);
6951:
6952: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
6953: {
6954: if(!(drive_num >= 0 && drive_num < 26)) {
6955: return(0);
6956: }
6957: pcbios_update_drive_param(drive_num, force_update);
6958:
6959: drive_param_t *drive_param = &drive_params[drive_num];
6960: *seg = DPB_TOP >> 4;
6961: *ofs = sizeof(dpb_t) * drive_num;
6962: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
6963:
6964: memset(dpb, 0, sizeof(dpb_t));
6965:
6966: dpb->drive_num = drive_num;
6967: dpb->unit_num = drive_num;
6968:
6969: if(drive_param->valid) {
6970: DISK_GEOMETRY *geo = &drive_param->geometry;
6971:
6972: dpb->bytes_per_sector = (UINT16)geo->BytesPerSector;
6973: dpb->highest_sector_num = (UINT8)(geo->SectorsPerTrack - 1);
6974: dpb->highest_cluster_num = (UINT16)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6975: dpb->maximum_cluster_num = (UINT32)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6976: switch(geo->MediaType) {
6977: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6978: dpb->media_type = 0xff;
6979: break;
6980: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6981: dpb->media_type = 0xfe;
6982: break;
6983: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6984: dpb->media_type = 0xfd;
6985: break;
6986: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6987: dpb->media_type = 0xfc;
6988: break;
6989: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6990: case F3_1Pt2_512:
6991: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6992: case F5_720_512:
6993: dpb->media_type = 0xf9;
6994: break;
6995: case FixedMedia: // hard disk
6996: case RemovableMedia:
6997: case Unknown:
6998: dpb->media_type = 0xf8;
6999: break;
7000: default:
7001: dpb->media_type = 0xf0;
7002: break;
7003: }
7004: }
7005: dpb->next_dpb_ofs = (drive_num == 25) ? 0xffff : *ofs + sizeof(dpb_t);
7006: dpb->next_dpb_seg = (drive_num == 25) ? 0xffff : *seg;
7007: dpb->info_sector = 0xffff;
7008: dpb->backup_boot_sector = 0xffff;
7009: dpb->free_clusters = 0xffff;
7010: dpb->free_search_cluster = 0xffffffff;
7011:
7012: return(drive_param->valid);
7013: }
7014:
7015: // pc bios
7016:
7017: #ifdef USE_SERVICE_THREAD
7018: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress)
7019: {
7020: #if defined(HAS_I386)
7021: if(m_SF != 0) {
7022: m_SF = 0;
7023: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4
7024: } else {
7025: m_SF = 1;
7026: mem[DUMMY_TOP + 0x15] = 0x78; // js -4
7027: }
7028: #else
7029: if(m_SignVal < 0) {
7030: m_SignVal = 0;
7031: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4
7032: } else {
7033: m_SignVal = -1;
7034: mem[DUMMY_TOP + 0x15] = 0x78; // js -4
7035: }
7036: #endif
7037: // dummy loop to wait BIOS/DOS service is done is at fffc:0013
7038: i386_call_far(DUMMY_TOP >> 4, 0x0013);
7039: in_service = true;
7040: service_exit = false;
7041: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL));
7042: }
7043:
7044: void finish_service_loop()
7045: {
7046: if(in_service && service_exit) {
7047: #if defined(HAS_I386)
7048: if(m_SF != 0) {
7049: m_SF = 0;
7050: } else {
7051: m_SF = 1;
7052: }
7053: #else
7054: if(m_SignVal < 0) {
7055: m_SignVal = 0;
7056: } else {
7057: m_SignVal = -1;
7058: }
7059: #endif
7060: in_service = false;
7061: }
7062: }
7063: #endif
7064:
7065: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
7066: {
7067: static unsigned __int64 start_msec_since_midnight = 0;
7068: static unsigned __int64 start_msec_since_hostboot = 0;
7069:
7070: if(start_msec_since_midnight == 0) {
7071: SYSTEMTIME time;
7072: GetLocalTime(&time);
7073: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
7074: start_msec_since_hostboot = cur_msec;
7075: }
7076: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
7077: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
7078: return (UINT32)tick;
7079: }
7080:
7081: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
7082: {
7083: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
7084: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
7085:
7086: if(prev_tick > next_tick) {
7087: mem[0x470] = 1;
7088: }
7089: *(UINT32 *)(mem + 0x46c) = next_tick;
7090: }
7091:
7092: inline void pcbios_irq0()
7093: {
7094: //++*(UINT32 *)(mem + 0x46c);
7095: pcbios_update_daily_timer_counter(timeGetTime());
7096: }
7097:
7098: int pcbios_get_text_vram_address(int page)
7099: {
7100: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
7101: return TEXT_VRAM_TOP;
7102: } else {
7103: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
7104: }
7105: }
7106:
7107: int pcbios_get_shadow_buffer_address(int page)
7108: {
7109: if(!int_10h_feh_called) {
7110: return pcbios_get_text_vram_address(page);
7111: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
7112: return SHADOW_BUF_TOP;
7113: } else {
7114: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
7115: }
7116: }
7117:
7118: int pcbios_get_shadow_buffer_address(int page, int x, int y)
7119: {
7120: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
7121: }
7122:
7123: bool pcbios_set_font_size(int width, int height)
7124: {
7125: if(set_console_font_size(width, height)) {
7126: *(UINT16 *)(mem + 0x485) = height;
7127: return(true);
7128: }
7129: return(false);
7130: }
7131:
7132: void pcbios_set_console_size(int width, int height, bool clr_screen)
7133: {
7134: // clear the existing screen, not just the new one
7135: int clr_height = max(height, scr_height);
7136:
7137: if(scr_width != width || scr_height != height) {
7138: change_console_size(width, height);
7139: }
7140: mem[0x462] = 0;
7141: *(UINT16 *)(mem + 0x44e) = 0;
7142:
7143: text_vram_top_address = pcbios_get_text_vram_address(0);
7144: text_vram_end_address = text_vram_top_address + width * height * 2;
7145: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
7146: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
7147: cursor_position_address = 0x450 + mem[0x462] * 2;
7148:
7149: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7150: if(clr_screen) {
7151: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
7152: mem[ofs++] = 0x20;
7153: mem[ofs++] = 0x07;
7154: }
7155:
7156: #ifdef USE_VRAM_THREAD
7157: EnterCriticalSection(&vram_crit_sect);
7158: #endif
7159: for(int y = 0; y < clr_height; y++) {
7160: for(int x = 0; x < scr_width; x++) {
7161: SCR_BUF(y,x).Char.AsciiChar = ' ';
7162: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
7163: }
7164: }
7165: SMALL_RECT rect;
7166: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
7167: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7168: vram_length_char = vram_last_length_char = 0;
7169: vram_length_attr = vram_last_length_attr = 0;
7170: #ifdef USE_VRAM_THREAD
7171: LeaveCriticalSection(&vram_crit_sect);
7172: #endif
7173: }
7174: COORD co;
7175: co.X = 0;
7176: co.Y = scr_top;
7177: SetConsoleCursorPosition(hStdout, co);
7178: cursor_moved = true;
7179: cursor_moved_by_crtc = false;
7180: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
7181: }
7182:
7183: void pcbios_update_cursor_position()
7184: {
7185: CONSOLE_SCREEN_BUFFER_INFO csbi;
7186: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
7187: if(!restore_console_on_exit) {
7188: scr_top = csbi.srWindow.Top;
7189: }
7190: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
7191: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
7192: }
7193:
7194: inline void pcbios_int_10h_00h()
7195: {
7196: switch(REG8(AL) & 0x7f) {
7197: case 0x70: // v-text mode
7198: case 0x71: // extended cga v-text mode
7199: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
7200: break;
7201: case 0x73:
7202: case 0x03:
7203: change_console_size(80, 25); // for Windows10
7204: pcbios_set_font_size(font_width, font_height);
7205: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
7206: break;
7207: }
7208: if(REG8(AL) & 0x80) {
7209: mem[0x487] |= 0x80;
7210: } else {
7211: mem[0x487] &= ~0x80;
7212: }
7213: mem[0x449] = REG8(AL) & 0x7f;
7214: }
7215:
7216: inline void pcbios_int_10h_01h()
7217: {
7218: mem[0x460] = REG8(CL);
7219: mem[0x461] = REG8(CH);
7220:
7221: int size = (int)(REG8(CL) & 7) - (int)(REG8(CH) & 7) + 1;
7222:
7223: if(!((REG8(CH) & 0x20) != 0 || size < 0)) {
7224: ci_new.bVisible = TRUE;
7225: ci_new.dwSize = (size + 2) * 100 / (8 + 2);
7226: } else {
7227: ci_new.bVisible = FALSE;
7228: }
7229: }
7230:
7231: inline void pcbios_int_10h_02h()
7232: {
7233: // continuously setting the cursor effectively stops it blinking
7234: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2] || cursor_moved_by_crtc)) {
7235: COORD co;
7236: co.X = REG8(DL);
7237: co.Y = REG8(DH) + scr_top;
7238:
7239: // some programs hide the cursor by moving it off screen
7240: static bool hidden = false;
7241: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7242:
7243: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
7244: if(ci_new.bVisible) {
7245: ci_new.bVisible = FALSE;
7246: hidden = true;
7247: }
7248: } else if(hidden) {
7249: if(!ci_new.bVisible) {
7250: ci_new.bVisible = TRUE;
7251: }
7252: hidden = false;
7253: }
7254: cursor_moved_by_crtc = false;
7255: }
7256: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
7257: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
7258: }
7259:
7260: inline void pcbios_int_10h_03h()
7261: {
7262: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7263: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7264: REG8(CL) = mem[0x460];
7265: REG8(CH) = mem[0x461];
7266: }
7267:
7268: inline void pcbios_int_10h_05h()
7269: {
7270: if(REG8(AL) >= vram_pages) {
7271: return;
7272: }
7273: if(mem[0x462] != REG8(AL)) {
7274: vram_flush();
7275:
7276: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7277: SMALL_RECT rect;
7278: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
7279: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7280:
7281: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
7282: for(int x = 0; x < scr_width; x++) {
7283: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
7284: mem[ofs++] = SCR_BUF(y,x).Attributes;
7285: }
7286: }
7287: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
7288: for(int x = 0; x < scr_width; x++) {
7289: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
7290: SCR_BUF(y,x).Attributes = mem[ofs++];
7291: }
7292: }
7293: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7294:
7295: COORD co;
7296: co.X = mem[0x450 + REG8(AL) * 2];
7297: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
7298: if(co.Y < scr_top + scr_height) {
7299: SetConsoleCursorPosition(hStdout, co);
7300: }
7301: cursor_moved_by_crtc = false;
7302: }
7303: mem[0x462] = REG8(AL);
7304: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
7305: int regen = min(scr_width * scr_height * 2, 0x8000);
7306: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
7307: text_vram_end_address = text_vram_top_address + regen;
7308: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
7309: shadow_buffer_end_address = shadow_buffer_top_address + regen;
7310: cursor_position_address = 0x450 + mem[0x462] * 2;
7311: }
7312:
7313: inline void pcbios_int_10h_06h()
7314: {
7315: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
7316: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
7317: return;
7318: }
7319: vram_flush();
7320:
7321: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7322: SMALL_RECT rect;
7323: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
7324: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7325:
7326: int right = min(REG8(DL), scr_width - 1);
7327: int bottom = min(REG8(DH), scr_height - 1);
7328:
7329: if(REG8(AL) == 0) {
7330: for(int y = REG8(CH); y <= bottom; y++) {
7331: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
7332: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
7333: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
7334: }
7335: }
7336: } else {
7337: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
7338: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
7339: if(y2 <= bottom) {
7340: SCR_BUF(y,x) = SCR_BUF(y2,x);
7341: } else {
7342: SCR_BUF(y,x).Char.AsciiChar = ' ';
7343: SCR_BUF(y,x).Attributes = REG8(BH);
7344: }
7345: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
7346: mem[ofs++] = SCR_BUF(y,x).Attributes;
7347: }
7348: }
7349: }
7350: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7351: }
7352:
7353: inline void pcbios_int_10h_07h()
7354: {
7355: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
7356: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
7357: return;
7358: }
7359: vram_flush();
7360:
7361: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7362: SMALL_RECT rect;
7363: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
7364: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7365:
7366: int right = min(REG8(DL), scr_width - 1);
7367: int bottom = min(REG8(DH), scr_height - 1);
7368:
7369: if(REG8(AL) == 0) {
7370: for(int y = REG8(CH); y <= bottom; y++) {
7371: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
7372: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
7373: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
7374: }
7375: }
7376: } else {
7377: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
7378: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
7379: if(y2 >= REG8(CH)) {
7380: SCR_BUF(y,x) = SCR_BUF(y2,x);
7381: } else {
7382: SCR_BUF(y,x).Char.AsciiChar = ' ';
7383: SCR_BUF(y,x).Attributes = REG8(BH);
7384: }
7385: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
7386: mem[ofs++] = SCR_BUF(y,x).Attributes;
7387: }
7388: }
7389: }
7390: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7391: }
7392:
7393: inline void pcbios_int_10h_08h()
7394: {
7395: COORD co;
7396: DWORD num;
7397:
7398: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7399: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7400:
7401: if(mem[0x462] == REG8(BH)) {
7402: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7403: co.Y += scr_top;
7404: vram_flush();
7405: ReadConsoleOutputCharacterA(hStdout, scr_char, 1, co, &num);
7406: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
7407: REG8(AL) = scr_char[0];
7408: REG8(AH) = scr_attr[0];
7409: } else {
7410: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
7411: }
7412: }
7413:
7414: inline void pcbios_int_10h_09h()
7415: {
7416: COORD co;
7417:
7418: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7419: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7420:
7421: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
7422: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
7423:
7424: if(mem[0x462] == REG8(BH)) {
7425: #ifdef USE_VRAM_THREAD
7426: EnterCriticalSection(&vram_crit_sect);
7427: #endif
7428: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
7429: while(dest < end) {
7430: write_text_vram_char(dest - vram, REG8(AL));
7431: mem[dest++] = REG8(AL);
7432: write_text_vram_attr(dest - vram, REG8(BL));
7433: mem[dest++] = REG8(BL);
7434: }
7435: #ifdef USE_VRAM_THREAD
7436: LeaveCriticalSection(&vram_crit_sect);
7437: #endif
7438: } else {
7439: while(dest < end) {
7440: mem[dest++] = REG8(AL);
7441: mem[dest++] = REG8(BL);
7442: }
7443: }
7444: }
7445:
7446: inline void pcbios_int_10h_0ah()
7447: {
7448: COORD co;
7449:
7450: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7451: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7452:
7453: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
7454: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
7455:
7456: if(mem[0x462] == REG8(BH)) {
7457: #ifdef USE_VRAM_THREAD
7458: EnterCriticalSection(&vram_crit_sect);
7459: #endif
7460: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
7461: while(dest < end) {
7462: write_text_vram_char(dest - vram, REG8(AL));
7463: mem[dest++] = REG8(AL);
7464: dest++;
7465: }
7466: #ifdef USE_VRAM_THREAD
7467: LeaveCriticalSection(&vram_crit_sect);
7468: #endif
7469: } else {
7470: while(dest < end) {
7471: mem[dest++] = REG8(AL);
7472: dest++;
7473: }
7474: }
7475: }
7476:
7477: inline void pcbios_int_10h_0ch()
7478: {
7479: HDC hdc = get_console_window_device_context();
7480:
7481: if(hdc != NULL) {
7482: BYTE r = (REG8(AL) & 2) ? 255 : 0;
7483: BYTE g = (REG8(AL) & 4) ? 255 : 0;
7484: BYTE b = (REG8(AL) & 1) ? 255 : 0;
7485:
7486: if(REG8(AL) & 0x80) {
7487: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
7488: if(color != CLR_INVALID) {
7489: r ^= ((DWORD)color & 0x0000ff) ? 255 : 0;
7490: g ^= ((DWORD)color & 0x00ff00) ? 255 : 0;
7491: b ^= ((DWORD)color & 0xff0000) ? 255 : 0;
7492: }
7493: }
7494: SetPixel(hdc, REG16(CX), REG16(DX), RGB(r, g, b));
7495: }
7496: }
7497:
7498: inline void pcbios_int_10h_0dh()
7499: {
7500: HDC hdc = get_console_window_device_context();
7501: BYTE r = 0;
7502: BYTE g = 0;
7503: BYTE b = 0;
7504:
7505: if(hdc != NULL) {
7506: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
7507: if(color != CLR_INVALID) {
7508: r = ((DWORD)color & 0x0000ff) ? 255 : 0;
7509: g = ((DWORD)color & 0x00ff00) ? 255 : 0;
7510: b = ((DWORD)color & 0xff0000) ? 255 : 0;
7511: }
7512: }
7513: REG8(AL) = ((b != 0) ? 1 : 0) | ((r != 0) ? 2 : 0) | ((g != 0) ? 4 : 0);
7514: }
7515:
7516: inline void pcbios_int_10h_0eh()
7517: {
7518: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7519: CONSOLE_SCREEN_BUFFER_INFO csbi;
7520: DWORD num;
7521: COORD co;
7522:
7523: if(cursor_moved_by_crtc) {
7524: if(!restore_console_on_exit) {
7525: GetConsoleScreenBufferInfo(hStdout, &csbi);
7526: scr_top = csbi.srWindow.Top;
7527: }
7528: co.X = mem[0x450 + REG8(BH) * 2];
7529: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
7530: SetConsoleCursorPosition(hStdout, co);
7531: cursor_moved_by_crtc = false;
7532: }
7533: co.X = mem[0x450 + mem[0x462] * 2];
7534: co.Y = mem[0x451 + mem[0x462] * 2];
7535:
7536: if(REG8(AL) == 7) {
7537: //MessageBeep(-1);
7538: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
7539: if(REG8(AL) == 10) {
7540: vram_flush();
7541: }
7542: WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
7543: cursor_moved = true;
7544: } else {
7545: int dest = pcbios_get_shadow_buffer_address(mem[0x462], co.X, co.Y);
7546: #ifdef USE_VRAM_THREAD
7547: EnterCriticalSection(&vram_crit_sect);
7548: #endif
7549: int vram = pcbios_get_shadow_buffer_address(mem[0x462]);
7550: write_text_vram_char(dest - vram, REG8(AL));
7551: #ifdef USE_VRAM_THREAD
7552: LeaveCriticalSection(&vram_crit_sect);
7553: #endif
7554:
7555: if(++co.X == scr_width) {
7556: co.X = 0;
7557: if(++co.Y == scr_height) {
7558: vram_flush();
7559: WriteConsoleA(hStdout, "\n", 1, &num, NULL);
7560: cursor_moved = true;
7561: }
7562: }
7563: if(!cursor_moved) {
7564: co.Y += scr_top;
7565: SetConsoleCursorPosition(hStdout, co);
7566: cursor_moved = true;
7567: }
7568: mem[dest] = REG8(AL);
7569: }
7570: }
7571:
7572: inline void pcbios_int_10h_0fh()
7573: {
7574: REG8(AL) = mem[0x449];
7575: REG8(AH) = mem[0x44a];
7576: REG8(BH) = mem[0x462];
7577: }
7578:
7579: inline void pcbios_int_10h_11h()
7580: {
7581: switch(REG8(AL)) {
7582: case 0x00:
7583: case 0x10:
7584: if(REG8(BH)) {
7585: change_console_size(80, 25); // for Windows10
7586: if(!pcbios_set_font_size(font_width, (int)REG8(BH))) {
7587: for(int h = min(font_height, (int)REG8(BH)); h <= max(font_height, (int)REG8(BH)); h++) {
7588: if(h != (int)REG8(BH)) {
7589: if(pcbios_set_font_size(font_width, h)) {
7590: break;
7591: }
7592: }
7593: }
7594: }
7595: pcbios_set_console_size(80, (25 * 16) / REG8(BH), true);
7596: }
7597: break;
7598: case 0x01:
7599: case 0x11:
7600: change_console_size(80, 28); // for Windows10
7601: if(!pcbios_set_font_size(font_width, 14)) {
7602: for(int h = min(font_height, 14); h <= max(font_height, 14); h++) {
7603: if(h != 14) {
7604: if(pcbios_set_font_size(font_width, h)) {
7605: break;
7606: }
7607: }
7608: }
7609: }
7610: pcbios_set_console_size(80, 28, true); // 28 = 25 * 16 / 14
7611: break;
7612: case 0x02:
7613: case 0x12:
7614: change_console_size(80, 25); // for Windows10
7615: if(!pcbios_set_font_size(8, 8)) {
7616: bool success = false;
7617: for(int y = 8; y <= 14; y++) {
7618: for(int x = min(font_width, 6); x <= max(font_width, 8); x++) {
7619: if(pcbios_set_font_size(x, y)) {
7620: success = true;
7621: break;
7622: }
7623: }
7624: }
7625: if(!success) {
7626: pcbios_set_font_size(font_width, font_height);
7627: }
7628: }
7629: pcbios_set_console_size(80, 50, true); // 50 = 25 * 16 / 8
7630: break;
7631: case 0x04:
7632: case 0x14:
7633: change_console_size(80, 25); // for Windows10
7634: pcbios_set_font_size(font_width, font_height);
7635: pcbios_set_console_size(80, 25, true);
7636: break;
7637: case 0x18:
7638: change_console_size(80, 25); // for Windows10
7639: pcbios_set_font_size(font_width, font_height);
7640: pcbios_set_console_size(80, 25, true);
7641: break;
7642: case 0x30:
7643: SREG(ES) = 0;
7644: i386_load_segment_descriptor(ES);
7645: REG16(BP) = 0;
7646: REG16(CX) = mem[0x485];
7647: REG8(DL) = mem[0x484];
7648: break;
7649: default:
7650: 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));
7651: m_CF = 1;
7652: break;
7653: }
7654: }
7655:
7656: inline void pcbios_int_10h_12h()
7657: {
7658: switch(REG8(BL)) {
7659: case 0x10:
7660: REG16(BX) = 0x0003;
7661: REG16(CX) = 0x0009;
7662: break;
7663: }
7664: }
7665:
7666: inline void pcbios_int_10h_13h()
7667: {
7668: int ofs = SREG_BASE(ES) + REG16(BP);
7669: COORD co;
7670: DWORD num;
7671:
7672: co.X = REG8(DL);
7673: co.Y = REG8(DH) + scr_top;
7674:
7675: vram_flush();
7676:
7677: switch(REG8(AL)) {
7678: case 0x00:
7679: case 0x01:
7680: if(mem[0x462] == REG8(BH)) {
7681: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7682: CONSOLE_SCREEN_BUFFER_INFO csbi;
7683: GetConsoleScreenBufferInfo(hStdout, &csbi);
7684: SetConsoleCursorPosition(hStdout, co);
7685:
7686: if(csbi.wAttributes != REG8(BL)) {
7687: SetConsoleTextAttribute(hStdout, REG8(BL));
7688: }
7689: WriteConsoleA(hStdout, &mem[ofs], REG16(CX), &num, NULL);
7690:
7691: if(csbi.wAttributes != REG8(BL)) {
7692: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7693: }
7694: if(REG8(AL) == 0x00) {
7695: if(!restore_console_on_exit) {
7696: GetConsoleScreenBufferInfo(hStdout, &csbi);
7697: scr_top = csbi.srWindow.Top;
7698: }
7699: co.X = mem[0x450 + REG8(BH) * 2];
7700: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
7701: SetConsoleCursorPosition(hStdout, co);
7702: } else {
7703: cursor_moved = true;
7704: }
7705: cursor_moved_by_crtc = false;
7706: } else {
7707: m_CF = 1;
7708: }
7709: break;
7710: case 0x02:
7711: case 0x03:
7712: if(mem[0x462] == REG8(BH)) {
7713: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7714: CONSOLE_SCREEN_BUFFER_INFO csbi;
7715: GetConsoleScreenBufferInfo(hStdout, &csbi);
7716: SetConsoleCursorPosition(hStdout, co);
7717:
7718: WORD wAttributes = csbi.wAttributes;
7719: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
7720: if(wAttributes != mem[ofs + 1]) {
7721: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
7722: wAttributes = mem[ofs + 1];
7723: }
7724: WriteConsoleA(hStdout, &mem[ofs], 1, &num, NULL);
7725: }
7726: if(csbi.wAttributes != wAttributes) {
7727: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7728: }
7729: if(REG8(AL) == 0x02) {
7730: co.X = mem[0x450 + REG8(BH) * 2];
7731: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
7732: SetConsoleCursorPosition(hStdout, co);
7733: } else {
7734: cursor_moved = true;
7735: }
7736: cursor_moved_by_crtc = false;
7737: } else {
7738: m_CF = 1;
7739: }
7740: break;
7741: case 0x10:
7742: case 0x11:
7743: if(mem[0x462] == REG8(BH)) {
7744: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7745: ReadConsoleOutputCharacterA(hStdout, scr_char, REG16(CX), co, &num);
7746: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
7747: for(int i = 0; i < num; i++) {
7748: mem[ofs++] = scr_char[i];
7749: mem[ofs++] = scr_attr[i];
7750: if(REG8(AL) & 0x01) {
7751: mem[ofs++] = 0;
7752: mem[ofs++] = 0;
7753: }
7754: }
7755: } else {
7756: for(int i = 0, src = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
7757: mem[ofs++] = mem[src++];
7758: mem[ofs++] = mem[src++];
7759: if(REG8(AL) & 0x01) {
7760: mem[ofs++] = 0;
7761: mem[ofs++] = 0;
7762: }
7763: if(++co.X == scr_width) {
7764: if(++co.Y == scr_height) {
7765: break;
7766: }
7767: co.X = 0;
7768: }
7769: }
7770: }
7771: break;
7772: case 0x12: // ???
7773: case 0x13: // ???
7774: case 0x20:
7775: case 0x21:
7776: if(mem[0x462] == REG8(BH)) {
7777: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7778: int len = min(REG16(CX), scr_width * scr_height);
7779: for(int i = 0; i < len; i++) {
7780: scr_char[i] = mem[ofs++];
7781: scr_attr[i] = mem[ofs++];
7782: if(REG8(AL) & 0x01) {
7783: ofs += 2;
7784: }
7785: }
7786: WriteConsoleOutputCharacterA(hStdout, scr_char, len, co, &num);
7787: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
7788: } else {
7789: for(int i = 0, dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
7790: mem[dest++] = mem[ofs++];
7791: mem[dest++] = mem[ofs++];
7792: if(REG8(AL) & 0x01) {
7793: ofs += 2;
7794: }
7795: if(++co.X == scr_width) {
7796: if(++co.Y == scr_height) {
7797: break;
7798: }
7799: co.X = 0;
7800: }
7801: }
7802: }
7803: break;
7804: default:
7805: 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));
7806: m_CF = 1;
7807: break;
7808: }
7809: }
7810:
7811: inline void pcbios_int_10h_18h()
7812: {
7813: switch(REG8(AL)) {
7814: case 0x00:
7815: case 0x01:
7816: // REG8(AL) = 0x86;
7817: REG8(AL) = 0x00;
7818: break;
7819: default:
7820: 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));
7821: m_CF = 1;
7822: break;
7823: }
7824: }
7825:
7826: inline void pcbios_int_10h_1ah()
7827: {
7828: switch(REG8(AL)) {
7829: case 0x00:
7830: REG8(AL) = 0x1a;
7831: REG8(BL) = 0x08;
7832: REG8(BH) = 0x00;
7833: break;
7834: default:
7835: 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));
7836: m_CF = 1;
7837: break;
7838: }
7839: }
7840:
7841: inline void pcbios_int_10h_1dh()
7842: {
7843: switch(REG8(AL)) {
7844: case 0x00:
7845: // DOS/V Shift Status Line Control is not supported
7846: m_CF = 1;
7847: break;
7848: case 0x01:
7849: break;
7850: case 0x02:
7851: REG16(BX) = 0;
7852: break;
7853: default:
7854: 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));
7855: m_CF = 1;
7856: break;
7857: }
7858: }
7859:
7860: inline void pcbios_int_10h_4fh()
7861: {
7862: switch(REG8(AL)) {
7863: case 0x00:
7864: REG8(AH) = 0x02; // not supported
7865: break;
7866: case 0x01:
7867: case 0x02:
7868: case 0x03:
7869: case 0x04:
7870: case 0x05:
7871: case 0x06:
7872: case 0x07:
7873: case 0x08:
7874: case 0x09:
7875: case 0x0a:
7876: case 0x0b:
7877: case 0x0c:
7878: REG8(AH) = 0x01; // failed
7879: break;
7880: default:
7881: 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));
7882: m_CF = 1;
7883: break;
7884: }
7885: }
7886:
7887: inline void pcbios_int_10h_82h()
7888: {
7889: static UINT8 mode = 0;
7890:
7891: switch(REG8(AL)) {
7892: case 0x00:
7893: if(REG8(BL) != 0xff) {
7894: mode = REG8(BL);
7895: }
7896: REG8(AL) = mode;
7897: break;
7898: default:
7899: 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));
7900: m_CF = 1;
7901: break;
7902: }
7903: }
7904:
7905: inline void pcbios_int_10h_83h()
7906: {
7907: static UINT8 mode = 0;
7908:
7909: switch(REG8(AL)) {
7910: case 0x00:
7911: REG16(AX) = 0; // offset???
7912: SREG(ES) = (SHADOW_BUF_TOP >> 4);
7913: i386_load_segment_descriptor(ES);
7914: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
7915: break;
7916: default:
7917: 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));
7918: m_CF = 1;
7919: break;
7920: }
7921: }
7922:
7923: inline void pcbios_int_10h_90h()
7924: {
7925: REG8(AL) = mem[0x449];
7926: }
7927:
7928: inline void pcbios_int_10h_91h()
7929: {
7930: REG8(AL) = 0x04; // VGA
7931: }
7932:
7933: inline void pcbios_int_10h_efh()
7934: {
7935: REG16(DX) = 0xffff;
7936: }
7937:
7938: inline void pcbios_int_10h_feh()
7939: {
7940: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
7941: SREG(ES) = (SHADOW_BUF_TOP >> 4);
7942: i386_load_segment_descriptor(ES);
7943: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
7944: }
7945: int_10h_feh_called = true;
7946: }
7947:
7948: inline void pcbios_int_10h_ffh()
7949: {
7950: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
7951: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
7952: COORD co;
7953: DWORD num;
7954:
7955: vram_flush();
7956:
7957: co.X = (REG16(DI) >> 1) % scr_width;
7958: co.Y = (REG16(DI) >> 1) / scr_width;
7959: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
7960: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
7961: int len;
7962: for(len = 0; ofs < end; len++) {
7963: scr_char[len] = mem[ofs++];
7964: scr_attr[len] = mem[ofs++];
7965: }
7966: co.Y += scr_top;
7967: WriteConsoleOutputCharacterA(hStdout, scr_char, len, co, &num);
7968: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
7969: }
7970: int_10h_ffh_called = true;
7971: }
7972:
7973: int pcbios_update_drive_param(int drive_num, int force_update)
7974: {
7975: if(drive_num >= 0 && drive_num < 26) {
7976: drive_param_t *drive_param = &drive_params[drive_num];
7977:
7978: if(force_update || !drive_param->initialized) {
7979: drive_param->valid = 0;
7980: char dev[64];
7981: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7982:
7983: HANDLE hFile = CreateFileA(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7984: if(hFile != INVALID_HANDLE_VALUE) {
7985: DWORD dwSize;
7986: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &drive_param->geometry, sizeof(DISK_GEOMETRY), &dwSize, NULL)) {
7987: drive_param->valid = 1;
7988: }
7989: CloseHandle(hFile);
7990: }
7991: drive_param->initialized = 1;
7992: }
7993: return(drive_param->valid);
7994: }
7995: return(0);
7996: }
7997:
7998: inline void pcbios_int_13h_00h()
7999: {
8000: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
8001:
8002: if(pcbios_update_drive_param(drive_num, 1)) {
8003: REG8(AH) = 0x00; // successful completion
8004: } else {
8005: if(REG8(DL) & 0x80) {
8006: REG8(AH) = 0x05; // reset failed (hard disk)
8007: } else {
8008: REG8(AH) = 0x80; // timeout (not ready)
8009: }
8010: m_CF = 1;
8011: }
8012: }
8013:
8014: inline void pcbios_int_13h_02h()
8015: {
8016: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
8017:
8018: if(REG8(AL) == 0) {
8019: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
8020: m_CF = 1;
8021: } else if(!pcbios_update_drive_param(drive_num, 0)) {
8022: REG8(AH) = 0xff; // sense operation failed (hard disk)
8023: m_CF = 1;
8024: } else {
8025: drive_param_t *drive_param = &drive_params[drive_num];
8026: DISK_GEOMETRY *geo = &drive_param->geometry;
8027: char dev[64];
8028: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
8029:
8030: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8031: if(hFile == INVALID_HANDLE_VALUE) {
8032: REG8(AH) = 0xff; // sense operation failed (hard disk)
8033: m_CF = 1;
8034: } else {
8035: UINT32 sector_num = REG8(AL);
8036: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
8037: UINT32 head = REG8(DH);
8038: UINT32 sector = REG8(CL) & 0x3f;
8039: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
8040: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
8041: DWORD dwSize;
8042:
8043: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8044: // REG8(AH) = 0xff; // sense operation failed (hard disk)
8045: // m_CF = 1;
8046: // } else
8047: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8048: REG8(AH) = 0x04; // sector not found/read error
8049: m_CF = 1;
8050: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
8051: REG8(AH) = 0x04; // sector not found/read error
8052: m_CF = 1;
8053: } else {
8054: REG8(AH) = 0x00; // successful completion
8055: }
8056: CloseHandle(hFile);
8057: }
8058: }
8059: }
8060:
8061: inline void pcbios_int_13h_03h()
8062: {
8063: // this operation may cause serious damage for drives, so support only floppy disk...
8064: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
8065:
8066: if(REG8(AL) == 0) {
8067: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
8068: m_CF = 1;
8069: } else if(!pcbios_update_drive_param(drive_num, 0)) {
8070: REG8(AH) = 0xff; // sense operation failed (hard disk)
8071: m_CF = 1;
8072: } else if(!drive_params[drive_num].is_fdd()) {
8073: REG8(AH) = 0xff; // sense operation failed (hard disk)
8074: m_CF = 1;
8075: } else {
8076: drive_param_t *drive_param = &drive_params[drive_num];
8077: DISK_GEOMETRY *geo = &drive_param->geometry;
8078: char dev[64];
8079: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
8080:
8081: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8082: if(hFile == INVALID_HANDLE_VALUE) {
8083: REG8(AH) = 0xff; // sense operation failed (hard disk)
8084: m_CF = 1;
8085: } else {
8086: UINT32 sector_num = REG8(AL);
8087: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
8088: UINT32 head = REG8(DH);
8089: UINT32 sector = REG8(CL) & 0x3f;
8090: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
8091: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
8092: DWORD dwSize;
8093:
8094: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8095: // REG8(AH) = 0xff; // sense operation failed (hard disk)
8096: // m_CF = 1;
8097: // } else
8098: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8099: REG8(AH) = 0x04; // sector not found/read error
8100: m_CF = 1;
8101: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
8102: REG8(AH) = 0x04; // sector not found/read error
8103: m_CF = 1;
8104: } else {
8105: REG8(AH) = 0x00; // successful completion
8106: }
8107: CloseHandle(hFile);
8108: }
8109: }
8110: }
8111:
8112: inline void pcbios_int_13h_04h()
8113: {
8114: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
8115:
8116: if(REG8(AL) == 0) {
8117: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
8118: m_CF = 1;
8119: } else if(!pcbios_update_drive_param(drive_num, 0)) {
8120: REG8(AH) = 0xff; // sense operation failed (hard disk)
8121: m_CF = 1;
8122: } else {
8123: drive_param_t *drive_param = &drive_params[drive_num];
8124: DISK_GEOMETRY *geo = &drive_param->geometry;
8125: char dev[64];
8126: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
8127:
8128: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8129: if(hFile == INVALID_HANDLE_VALUE) {
8130: REG8(AH) = 0xff; // sense operation failed (hard disk)
8131: m_CF = 1;
8132: } else {
8133: UINT32 sector_num = REG8(AL);
8134: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
8135: UINT32 head = REG8(DH);
8136: UINT32 sector = REG8(CL) & 0x3f;
8137: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
8138: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
8139: DWORD dwSize;
8140: UINT8 *tmp_buffer = (UINT8 *)malloc(sector_num * geo->BytesPerSector);
8141:
8142: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8143: // REG8(AH) = 0xff; // sense operation failed (hard disk)
8144: // m_CF = 1;
8145: // } else
8146: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8147: REG8(AH) = 0x04; // sector not found/read error
8148: m_CF = 1;
8149: } else if(ReadFile(hFile, tmp_buffer, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
8150: REG8(AH) = 0x04; // sector not found/read error
8151: m_CF = 1;
8152: } else if(memcmp(mem + buffer_addr, tmp_buffer, sector_num * geo->BytesPerSector) != 0) {
8153: REG8(AH) = 0x05; // data did not verify correctly (TI Professional PC)
8154: m_CF = 1;
8155: } else {
8156: REG8(AH) = 0x00; // successful completion
8157: }
8158: free(tmp_buffer);
8159: CloseHandle(hFile);
8160: }
8161: }
8162: }
8163:
8164: inline void pcbios_int_13h_08h()
8165: {
8166: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
8167:
8168: if(pcbios_update_drive_param(drive_num, 1)) {
8169: drive_param_t *drive_param = &drive_params[drive_num];
8170: DISK_GEOMETRY *geo = &drive_param->geometry;
8171:
8172: REG16(AX) = 0x0000;
8173: switch(geo->MediaType) {
8174: case F5_360_512:
8175: case F5_320_512:
8176: case F5_320_1024:
8177: case F5_180_512:
8178: case F5_160_512:
8179: REG8(BL) = 0x01; // 320K/360K disk
8180: break;
8181: case F5_1Pt2_512:
8182: case F3_1Pt2_512:
8183: case F3_1Pt23_1024:
8184: case F5_1Pt23_1024:
8185: REG8(BL) = 0x02; // 1.2M disk
8186: break;
8187: case F3_720_512:
8188: case F3_640_512:
8189: case F5_640_512:
8190: case F5_720_512:
8191: REG8(BL) = 0x03; // 720K disk
8192: break;
8193: case F3_1Pt44_512:
8194: REG8(BL) = 0x04; // 1.44M disk
8195: break;
8196: case F3_2Pt88_512:
8197: REG8(BL) = 0x06; // 2.88M disk
8198: break;
8199: case RemovableMedia:
8200: REG8(BL) = 0x10; // ATAPI Removable Media Device
8201: break;
8202: default:
8203: REG8(BL) = 0x00; // unknown
8204: break;
8205: }
8206: if(REG8(DL) & 0x80) {
8207: switch(GetLogicalDrives() & 0x0c) {
8208: case 0x00: REG8(DL) = 0x00; break;
8209: case 0x04:
8210: case 0x08: REG8(DL) = 0x01; break;
8211: case 0x0c: REG8(DL) = 0x02; break;
8212: }
8213: } else {
8214: switch(GetLogicalDrives() & 0x03) {
8215: case 0x00: REG8(DL) = 0x00; break;
8216: case 0x01:
8217: case 0x02: REG8(DL) = 0x01; break;
8218: case 0x03: REG8(DL) = 0x02; break;
8219: }
8220: }
8221: REG8(DH) = drive_param->head_num();
8222: int cyl = (geo->Cylinders.QuadPart > 0x3ff) ? 0x3ff : geo->Cylinders.QuadPart;
8223: int sec = (geo->SectorsPerTrack > 0x3f) ? 0x3f : geo->SectorsPerTrack;
8224: REG8(CH) = cyl & 0xff;
8225: REG8(CL) = (sec & 0x3f) | ((cyl & 0x300) >> 2);
8226: } else {
8227: REG8(AH) = 0x07;
8228: m_CF = 1;
8229: }
8230: }
8231:
8232: inline void pcbios_int_13h_10h()
8233: {
8234: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
8235:
8236: if(pcbios_update_drive_param(drive_num, 1)) {
8237: REG8(AH) = 0x00; // successful completion
8238: } else {
8239: if(REG8(DL) & 0x80) {
8240: REG8(AH) = 0xaa; // drive not ready (hard disk)
8241: } else {
8242: REG8(AH) = 0x80; // timeout (not ready)
8243: }
8244: m_CF = 1;
8245: }
8246: }
8247:
8248: inline void pcbios_int_13h_15h()
8249: {
8250: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
8251:
8252: if(pcbios_update_drive_param(drive_num, 1)) {
8253: if(REG8(DL) & 0x80) {
8254: REG8(AH) = 0x02; // floppy (or other removable drive) with change-line support
8255: } else {
8256: REG8(AH) = 0x03; // hard disk
8257: }
8258: } else {
8259: REG8(AH) = 0x00; // no such drive
8260: }
8261: }
8262:
8263: inline void pcbios_int_13h_41h()
8264: {
8265: if(REG16(BX) == 0x55aa) {
8266: // IBM/MS INT 13 Extensions is not installed
8267: REG8(AH) = 0x01;
8268: m_CF = 1;
8269: } else {
8270: unimplemented_13h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x13, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8271: REG8(AH) = 0x01;
8272: m_CF = 1;
8273: }
8274: }
8275:
8276: inline void pcbios_int_14h_00h()
8277: {
8278: if(REG16(DX) < 4) {
8279: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
8280: UINT8 selector = sio_read(REG16(DX), 3);
8281: selector &= ~0x3f;
8282: selector |= REG8(AL) & 0x1f;
8283: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
8284: sio_write(REG16(DX), 3, selector | 0x80);
8285: sio_write(REG16(DX), 0, divisor & 0xff);
8286: sio_write(REG16(DX), 1, divisor >> 8);
8287: sio_write(REG16(DX), 3, selector);
8288: REG8(AH) = sio_read(REG16(DX), 5);
8289: REG8(AL) = sio_read(REG16(DX), 6);
8290: } else {
8291: REG8(AH) = 0x80;
8292: }
8293: }
8294:
8295: inline void pcbios_int_14h_01h()
8296: {
8297: if(REG16(DX) < 4) {
8298: UINT8 selector = sio_read(REG16(DX), 3);
8299: sio_write(REG16(DX), 3, selector & ~0x80);
8300: sio_write(REG16(DX), 0, REG8(AL));
8301: sio_write(REG16(DX), 3, selector);
8302: REG8(AH) = sio_read(REG16(DX), 5);
8303: } else {
8304: REG8(AH) = 0x80;
8305: }
8306: }
8307:
8308: inline void pcbios_int_14h_02h()
8309: {
8310: if(REG16(DX) < 4) {
8311: UINT8 selector = sio_read(REG16(DX), 3);
8312: sio_write(REG16(DX), 3, selector & ~0x80);
8313: REG8(AL) = sio_read(REG16(DX), 0);
8314: sio_write(REG16(DX), 3, selector);
8315: REG8(AH) = sio_read(REG16(DX), 5);
8316: } else {
8317: REG8(AH) = 0x80;
8318: }
8319: }
8320:
8321: inline void pcbios_int_14h_03h()
8322: {
8323: if(REG16(DX) < 4) {
8324: REG8(AH) = sio_read(REG16(DX), 5);
8325: REG8(AL) = sio_read(REG16(DX), 6);
8326: } else {
8327: REG8(AH) = 0x80;
8328: }
8329: }
8330:
8331: inline void pcbios_int_14h_04h()
8332: {
8333: if(REG16(DX) < 4) {
8334: UINT8 selector = sio_read(REG16(DX), 3);
8335: if(REG8(CH) <= 0x03) {
8336: selector = (selector & ~0x03) | REG8(CH);
8337: }
8338: if(REG8(BL) == 0x00) {
8339: selector &= ~0x04;
8340: } else if(REG8(BL) == 0x01) {
8341: selector |= 0x04;
8342: }
8343: if(REG8(BH) == 0x00) {
8344: selector = (selector & ~0x38) | 0x00;
8345: } else if(REG8(BH) == 0x01) {
8346: selector = (selector & ~0x38) | 0x08;
8347: } else if(REG8(BH) == 0x02) {
8348: selector = (selector & ~0x38) | 0x18;
8349: } else if(REG8(BH) == 0x03) {
8350: selector = (selector & ~0x38) | 0x28;
8351: } else if(REG8(BH) == 0x04) {
8352: selector = (selector & ~0x38) | 0x38;
8353: }
8354: if(REG8(AL) == 0x00) {
8355: selector |= 0x40;
8356: } else if(REG8(AL) == 0x01) {
8357: selector &= ~0x40;
8358: }
8359: if(REG8(CL) <= 0x0b) {
8360: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
8361: UINT16 divisor = 115200 / rate[REG8(CL)];
8362: sio_write(REG16(DX), 3, selector | 0x80);
8363: sio_write(REG16(DX), 0, divisor & 0xff);
8364: sio_write(REG16(DX), 1, divisor >> 8);
8365: }
8366: sio_write(REG16(DX), 3, selector);
8367: REG8(AH) = sio_read(REG16(DX), 5);
8368: REG8(AL) = sio_read(REG16(DX), 6);
8369: } else {
8370: REG8(AH) = 0x80;
8371: }
8372: }
8373:
8374: inline void pcbios_int_14h_05h()
8375: {
8376: if(REG16(DX) < 4) {
8377: if(REG8(AL) == 0x00) {
8378: REG8(BL) = sio_read(REG16(DX), 4);
8379: REG8(AH) = sio_read(REG16(DX), 5);
8380: REG8(AL) = sio_read(REG16(DX), 6);
8381: } else if(REG8(AL) == 0x01) {
8382: sio_write(REG16(DX), 4, REG8(BL));
8383: REG8(AH) = sio_read(REG16(DX), 5);
8384: REG8(AL) = sio_read(REG16(DX), 6);
8385: } else {
8386: 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));
8387: }
8388: } else {
8389: REG8(AH) = 0x80;
8390: }
8391: }
8392:
8393: inline void pcbios_int_15h_23h()
8394: {
8395: switch(REG8(AL)) {
8396: case 0x00:
8397: REG8(CL) = cmos_read(0x2d);
8398: REG8(CH) = cmos_read(0x2e);
8399: break;
8400: case 0x01:
8401: cmos_write(0x2d, REG8(CL));
8402: cmos_write(0x2e, REG8(CH));
8403: break;
8404: default:
8405: 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));
8406: REG8(AH) = 0x86;
8407: m_CF = 1;
8408: break;
8409: }
8410: }
8411:
8412: inline void pcbios_int_15h_24h()
8413: {
8414: switch(REG8(AL)) {
8415: case 0x00:
8416: i386_set_a20_line(0);
8417: REG8(AH) = 0;
8418: break;
8419: case 0x01:
8420: i386_set_a20_line(1);
8421: REG8(AH) = 0;
8422: break;
8423: case 0x02:
8424: REG8(AH) = 0;
8425: REG8(AL) = (m_a20_mask >> 20) & 1;
8426: REG16(CX) = 0;
8427: break;
8428: case 0x03:
8429: REG16(AX) = 0;
8430: REG16(BX) = 0;
8431: break;
8432: default:
8433: 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));
8434: REG8(AH) = 0x86;
8435: m_CF = 1;
8436: break;
8437: }
8438: }
8439:
8440: inline void pcbios_int_15h_49h()
8441: {
8442: REG8(AH) = 0x00;
8443: REG8(BL) = 0x00; // DOS/V
8444: // REG8(BL) = 0x01; // standard DBCS DOS (hardware DBCS support)
8445: }
8446:
8447: inline void pcbios_int_15h_50h()
8448: {
8449: switch(REG8(AL)) {
8450: case 0x00:
8451: case 0x01:
8452: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
8453: REG8(AH) = 0x01; // invalid font type in bh
8454: m_CF = 1;
8455: } else if(REG8(BL) != 0x00) {
8456: REG8(AH) = 0x02; // bl not zero
8457: m_CF = 1;
8458: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
8459: REG8(AH) = 0x04; // invalid code page
8460: m_CF = 1;
8461: } else if(REG8(AL) == 0x01) {
8462: REG8(AH) = 0x06; // font is read only
8463: m_CF = 1;
8464: } else {
8465: // dummy font read routine is at fffc:000d
8466: SREG(ES) = DUMMY_TOP >> 4;
8467: i386_load_segment_descriptor(ES);
8468: REG16(BX) = 0x000d;
8469: REG8(AH) = 0x00; // success
8470: }
8471: break;
8472: default:
8473: 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));
8474: REG8(AH) = 0x86;
8475: m_CF = 1;
8476: break;
8477: }
8478: }
8479:
8480: inline void pcbios_int_15h_53h()
8481: {
8482: switch(REG8(AL)) {
8483: case 0x00:
8484: // APM is not installed
8485: REG8(AH) = 0x86;
8486: m_CF = 1;
8487: break;
8488: default:
8489: 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));
8490: REG8(AH) = 0x86;
8491: m_CF = 1;
8492: break;
8493: }
8494: }
8495:
8496: inline void pcbios_int_15h_84h()
8497: {
8498: // joystick support (from DOSBox)
8499: switch(REG16(DX)) {
8500: case 0x00:
8501: REG16(AX) = 0x00f0;
8502: REG16(DX) = 0x0201;
8503: m_CF = 1;
8504: break;
8505: case 0x01:
8506: REG16(AX) = REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
8507: m_CF = 1;
8508: break;
8509: default:
8510: 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));
8511: REG8(AH) = 0x86;
8512: m_CF = 1;
8513: break;
8514: }
8515: }
8516:
8517: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID)
8518: {
8519: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
8520: UINT32 msec = usec / 1000;
8521:
8522: while(msec && !m_exit) {
8523: UINT32 tmp = min(msec, 100);
8524: if(msec - tmp < 10) {
8525: tmp = msec;
8526: }
8527: Sleep(tmp);
8528: msec -= tmp;
8529: }
8530:
8531: #ifdef USE_SERVICE_THREAD
8532: service_exit = true;
8533: #endif
8534: return(0);
8535: }
8536:
8537: inline void pcbios_int_15h_86h()
8538: {
8539: if(!(REG16(CX) == 0 && REG16(DX) == 0)) {
8540: #ifdef USE_SERVICE_THREAD
8541: if(!in_service && !in_service_29h) {
8542: start_service_loop(pcbios_int_15h_86h_thread);
8543: } else {
8544: #endif
8545: pcbios_int_15h_86h_thread(NULL);
8546: REQUEST_HARDWRE_UPDATE();
8547: #ifdef USE_SERVICE_THREAD
8548: }
8549: #endif
8550: }
8551: }
8552:
8553: inline void pcbios_int_15h_87h()
8554: {
8555: // copy extended memory (from DOSBox)
8556: int len = REG16(CX) * 2;
8557: int ofs = SREG_BASE(ES) + REG16(SI);
8558: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
8559: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
8560: memcpy(mem + dst, mem + src, len);
8561: REG16(AX) = 0x00;
8562: }
8563:
8564: inline void pcbios_int_15h_88h()
8565: {
8566: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
8567: }
8568:
8569: inline void pcbios_int_15h_89h()
8570: {
8571: #if defined(HAS_I286) || defined(HAS_I386)
8572: // switch to protected mode (from DOSBox)
8573: write_io_byte(0x20, 0x10);
8574: write_io_byte(0x21, REG8(BH));
8575: write_io_byte(0x21, 0x00);
8576: write_io_byte(0x21, 0xff);
8577: write_io_byte(0xa0, 0x10);
8578: write_io_byte(0xa1, REG8(BL));
8579: write_io_byte(0xa1, 0x00);
8580: write_io_byte(0xa1, 0xff);
8581: i386_set_a20_line(1);
8582: m_gdtr.limit = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x08);
8583: m_gdtr.base = *(UINT32 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x08 + 0x02) & 0xffffff;
8584: m_idtr.limit = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x10);
8585: m_idtr.base = *(UINT32 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x10 + 0x02) & 0xffffff;
8586: #if defined(HAS_I386)
8587: m_cr[0] |= 1;
8588: #else
8589: m_msw |= 1;
8590: #endif
8591: i386_sreg_load(0x18, DS, NULL);
8592: i386_sreg_load(0x20, ES, NULL);
8593: i386_sreg_load(0x28, SS, NULL);
8594: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
8595: REG16(SP) += 6; // clear stack of interrupt frame
8596: UINT32 flags = i386_get_flags();
8597: flags &= ~0x247fd5; // clear CF,PF,AF,ZF,SF,TF,IF,DF,OF,IOPL,NT,AC,ID
8598: i386_set_flags(flags);
8599: REG16(AX) = 0x00;
8600: i386_jmp_far(0x30, /*REG16(CX)*/offset);
8601: #else
8602: // i86/i186/v30: protected mode is not supported
8603: REG8(AH) = 0x86;
8604: m_CF = 1;
8605: #endif
8606: }
8607:
8608: inline void pcbios_int_15h_8ah()
8609: {
8610: UINT32 size = MAX_MEM - 0x100000;
8611: REG16(AX) = size & 0xffff;
8612: REG16(DX) = size >> 16;
8613: }
8614:
8615: #ifdef EXT_BIOS_TOP
8616: inline void pcbios_int_15h_c1h()
8617: {
8618: SREG(ES) = EXT_BIOS_TOP >> 4;
8619: i386_load_segment_descriptor(ES);
8620: }
8621: #endif
8622:
8623: void pcbios_read_from_ps2_mouse(UINT16 *data_1st, UINT16 *data_2nd, UINT16 *data_3rd)
8624: {
8625: // from DOSBox DoPS2Callback()
8626: UINT16 mdat = 0x08;
8627: INT16 xdiff = mouse.position.x - mouse.prev_position.x;
8628: INT16 ydiff = mouse.prev_position.y - mouse.position.y;
8629:
8630: #if 1
8631: if(xdiff > +16) xdiff = +16;
8632: if(xdiff < -16) xdiff = -16;
8633: if(ydiff > +16) ydiff = +16;
8634: if(ydiff < -16) ydiff = -16;
8635: #endif
8636:
8637: if(mouse.buttons[0].status) {
8638: mdat |= 0x01;
8639: }
8640: if(mouse.buttons[1].status) {
8641: mdat |= 0x02;
8642: }
8643: mouse.prev_position.x = mouse.position.x;
8644: mouse.prev_position.y = mouse.position.y;
8645:
8646: if((xdiff > 0xff) || (xdiff < -0xff)) {
8647: mdat |= 0x40; // x overflow
8648: }
8649: if((ydiff > 0xff) || (ydiff < -0xff)) {
8650: mdat |= 0x80; // y overflow
8651: }
8652: xdiff %= 256;
8653: ydiff %= 256;
8654: if(xdiff < 0) {
8655: xdiff = (0x100 + xdiff);
8656: mdat |= 0x10;
8657: }
8658: if(ydiff < 0) {
8659: ydiff = (0x100 + ydiff);
8660: mdat |= 0x20;
8661: }
8662: *data_1st = (UINT16)mdat;
8663: *data_2nd = (UINT16)(xdiff % 256);
8664: *data_3rd = (UINT16)(ydiff % 256);
8665: }
8666:
8667: inline void pcbios_int_15h_c2h()
8668: {
8669: static UINT8 sampling_rate = 5;
8670: static UINT8 resolution = 2;
8671: static UINT8 scaling = 1;
8672:
8673: switch(REG8(AL)) {
8674: case 0x00:
8675: if(REG8(BH) == 0x00) {
8676: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) {
8677: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS);
8678: } else {
8679: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
8680: }
8681: pic[1].imr |= 0x10; // disable irq12
8682: mouse.enabled_ps2 = false;
8683: REG8(AH) = 0x00; // successful
8684: } else if(REG8(BH) == 0x01) {
8685: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), (dwConsoleMode | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS) & ~ENABLE_QUICK_EDIT_MODE);
8686: pic[1].imr &= ~0x10; // enable irq12
8687: mouse.enabled_ps2 = true;
8688: REG8(AH) = 0x00; // successful
8689: } else {
8690: REG8(AH) = 0x01; // invalid function
8691: m_CF = 1;
8692: }
8693: break;
8694: case 0x01:
8695: REG8(BH) = 0x00; // device id
8696: REG8(BL) = 0xaa; // mouse
8697: case 0x05:
8698: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) {
8699: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS);
8700: } else {
8701: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
8702: }
8703: pic[1].imr |= 0x10; // disable irq12
8704: mouse.enabled_ps2 = false;
8705: sampling_rate = 5;
8706: resolution = 2;
8707: scaling = 1;
8708: REG8(AH) = 0x00; // successful
8709: break;
8710: case 0x02:
8711: sampling_rate = REG8(BH);
8712: REG8(AH) = 0x00; // successful
8713: break;
8714: case 0x03:
8715: resolution = REG8(BH);
8716: REG8(AH) = 0x00; // successful
8717: break;
8718: case 0x04:
8719: REG8(BH) = 0x00; // device id
8720: REG8(AH) = 0x00; // successful
8721: break;
8722: case 0x06:
8723: switch(REG8(BH)) {
8724: case 0x00:
8725: REG8(BL) = 0x00;
8726: if(mouse.buttons[1].status) {
8727: REG8(BL) |= 0x01;
8728: }
8729: if(mouse.buttons[0].status) {
8730: REG8(BL) |= 0x04;
8731: }
8732: if(scaling == 2) {
8733: REG8(BL) |= 0x10;
8734: }
8735: REG8(CL) = resolution;
8736: switch(sampling_rate) {
8737: case 0: REG8(DL) = 10; break;
8738: case 1: REG8(DL) = 20; break;
8739: case 2: REG8(DL) = 40; break;
8740: case 3: REG8(DL) = 60; break;
8741: case 4: REG8(DL) = 80; break;
8742: // case 5: REG8(DL) = 100; break;
8743: case 6: REG8(DL) = 200; break;
8744: default: REG8(DL) = 100; break;
8745: }
8746: REG8(AH) = 0x00; // successful
8747: break;
8748: case 0x01:
8749: case 0x02:
8750: scaling = REG8(BH);
8751: REG8(AH) = 0x00; // successful
8752: break;
8753: default:
8754: 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));
8755: REG8(AH) = 0x01; // invalid function
8756: m_CF = 1;
8757: break;
8758: }
8759: break;
8760: case 0x07: // set device handler addr
8761: mouse.call_addr_ps2.w.l = REG16(BX);
8762: mouse.call_addr_ps2.w.h = SREG(ES);
8763: REG8(AH) = 0x00; // successful
8764: break;
8765: case 0x08:
8766: REG8(AH) = 0x00; // successful
8767: break;
8768: case 0x09:
8769: {
8770: UINT16 data_1st, data_2nd, data_3rd;
8771: pcbios_read_from_ps2_mouse(&data_1st, &data_2nd, &data_3rd);
8772: REG8(BL) = (UINT8)(data_1st & 0xff);
8773: REG8(CL) = (UINT8)(data_2nd & 0xff);
8774: REG8(DL) = (UINT8)(data_3rd & 0xff);
8775: }
8776: REG8(AH) = 0x00; // successful
8777: break;
8778: default:
8779: 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));
8780: // REG8(AH) = 0x86;
8781: REG8(AH) = 0x01; // invalid function
8782: m_CF = 1;
8783: break;
8784: }
8785: }
8786:
8787: #if defined(HAS_I386)
8788: inline void pcbios_int_15h_c9h()
8789: {
8790: REG8(AH) = 0x00;
8791: REG8(CH) = cpu_type;
8792: REG8(CL) = cpu_step;
8793: }
8794: #endif
8795:
8796: inline void pcbios_int_15h_cah()
8797: {
8798: switch(REG8(AL)) {
8799: case 0x00:
8800: if(REG8(BL) > 0x3f) {
8801: REG8(AH) = 0x03;
8802: m_CF = 1;
8803: } else if(REG8(BL) < 0x0e) {
8804: REG8(AH) = 0x04;
8805: m_CF = 1;
8806: } else {
8807: REG8(CL) = cmos_read(REG8(BL));
8808: }
8809: break;
8810: case 0x01:
8811: if(REG8(BL) > 0x3f) {
8812: REG8(AH) = 0x03;
8813: m_CF = 1;
8814: } else if(REG8(BL) < 0x0e) {
8815: REG8(AH) = 0x04;
8816: m_CF = 1;
8817: } else {
8818: cmos_write(REG8(BL), REG8(CL));
8819: }
8820: break;
8821: default:
8822: 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));
8823: REG8(AH) = 0x86;
8824: m_CF = 1;
8825: break;
8826: }
8827: }
8828:
8829: inline void pcbios_int_15h_e8h()
8830: {
8831: switch(REG8(AL)) {
8832: case 0x01:
8833: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x0100000) >> 10);
8834: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
8835: break;
8836: #if defined(HAS_I386)
8837: case 0x20:
8838: if(REG32(EDX) == 0x534d4150 && REG32(ECX) >= 20) {
8839: if(REG32(EBX) < 3) {
8840: UINT32 base = 0, len = 0, type = 0;
8841: switch(REG32(EBX)) {
8842: case 0:
8843: base = 0x000000;
8844: len = MEMORY_END;
8845: type = 1;
8846: break;
8847: case 1:
8848: base = DUMMY_TOP;
8849: len = 0x100000 - DUMMY_TOP;
8850: type = 2;
8851: break;
8852: case 2:
8853: base = 0x100000;
8854: len = MAX_MEM - 0x100000;
8855: type = 1;
8856: break;
8857: }
8858: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x00) = base;
8859: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x04) = 0;
8860: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x08) = len;
8861: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x0c) = 0;
8862: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x10) = type;
8863:
8864: if(++REG32(EBX) >= 3) {
8865: REG32(EBX) = 0;
8866: }
8867: REG32(ECX) = 20;
8868: } else {
8869: m_CF = 1;
8870: }
8871: REG32(EAX) = 0x534d4150;
8872: break;
8873: }
8874: case 0x81:
8875: REG32(EAX) = REG32(ECX) = ((min(MAX_MEM, 0x1000000) - 0x0100000) >> 10);
8876: REG32(EBX) = REG32(EDX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
8877: break;
8878: #endif
8879: default:
8880: 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));
8881: REG8(AH) = 0x86;
8882: m_CF = 1;
8883: break;
8884: }
8885: }
8886:
8887: bool pcbios_is_key_buffer_empty()
8888: {
8889: return(*(UINT16 *)(mem + 0x41a) == *(UINT16 *)(mem + 0x41c));
8890: }
8891:
8892: void pcbios_clear_key_buffer()
8893: {
8894: key_buf_char->clear();
8895: key_buf_scan->clear();
8896:
8897: // update key buffer
8898: *(UINT16 *)(mem + 0x41a) = *(UINT16 *)(mem + 0x41c); // head = tail
8899: }
8900:
8901: void pcbios_set_key_buffer(int key_char, int key_scan)
8902: {
8903: // update key buffer
8904: UINT16 head = *(UINT16 *)(mem + 0x41a);
8905: UINT16 tail = *(UINT16 *)(mem + 0x41c);
8906: UINT16 next = tail + 2;
8907: if(next >= *(UINT16 *)(mem + 0x482)) {
8908: next = *(UINT16 *)(mem + 0x480);
8909: }
8910: if(next != head) {
8911: *(UINT16 *)(mem + 0x41c) = next;
8912: mem[0x400 + (tail++)] = key_char;
8913: mem[0x400 + (tail++)] = key_scan;
8914: } else {
8915: // store to extra key buffer
8916: if(key_buf_char != NULL && key_buf_scan != NULL) {
8917: key_buf_char->write(key_char);
8918: key_buf_scan->write(key_scan);
8919: }
8920: }
8921: }
8922:
8923: bool pcbios_get_key_buffer(int *key_char, int *key_scan)
8924: {
8925: // update key buffer
8926: UINT16 head = *(UINT16 *)(mem + 0x41a);
8927: UINT16 tail = *(UINT16 *)(mem + 0x41c);
8928: UINT16 next = head + 2;
8929: if(next >= *(UINT16 *)(mem + 0x482)) {
8930: next = *(UINT16 *)(mem + 0x480);
8931: }
8932: if(head != tail) {
8933: *(UINT16 *)(mem + 0x41a) = next;
8934: *key_char = mem[0x400 + (head++)];
8935: *key_scan = mem[0x400 + (head++)];
8936:
8937: // restore from extra key buffer
8938: if(key_buf_char != NULL && key_buf_scan != NULL) {
8939: if(!key_buf_char->empty()) {
8940: pcbios_set_key_buffer(key_buf_char->read(), key_buf_scan->read());
8941: }
8942: }
8943: return(true);
8944: } else {
8945: *key_char = 0x00;
8946: *key_scan = 0x00;
8947: return(false);
8948: }
8949: }
8950:
8951: bool pcbios_check_key_buffer(int *key_char, int *key_scan)
8952: {
8953: // do not remove from key buffer
8954: UINT16 head = *(UINT16 *)(mem + 0x41a);
8955: UINT16 tail = *(UINT16 *)(mem + 0x41c);
8956: if(head != tail) {
8957: *key_char = mem[0x400 + (head++)];
8958: *key_scan = mem[0x400 + (head++)];
8959: return(true);
8960: } else {
8961: *key_char = 0x00;
8962: *key_scan = 0x00;
8963: return(false);
8964: }
8965: }
8966:
8967: void pcbios_update_key_code(bool wait)
8968: {
8969: if(key_buf_char != NULL && key_buf_scan != NULL) {
8970: #ifdef USE_SERVICE_THREAD
8971: EnterCriticalSection(&key_buf_crit_sect);
8972: #endif
8973: bool empty = pcbios_is_key_buffer_empty();
8974: #ifdef USE_SERVICE_THREAD
8975: LeaveCriticalSection(&key_buf_crit_sect);
8976: #endif
8977: if(empty) {
8978: if(!update_key_buffer()) {
8979: if(wait) {
8980: Sleep(10);
8981: } else {
8982: maybe_idle();
8983: }
8984: }
8985: }
8986: }
8987: if(key_buf_char != NULL && key_buf_scan != NULL) {
8988: #ifdef USE_SERVICE_THREAD
8989: EnterCriticalSection(&key_buf_crit_sect);
8990: #endif
8991: int key_char, key_scan;
8992: if(pcbios_get_key_buffer(&key_char, &key_scan)) {
8993: key_code = key_char << 0;
8994: key_code |= key_scan << 8;
8995: key_recv = 0x0000ffff;
8996: }
8997: if(pcbios_get_key_buffer(&key_char, &key_scan)) {
8998: key_code |= key_char << 16;
8999: key_code |= key_scan << 24;
9000: key_recv |= 0xffff0000;
9001: }
9002: #ifdef USE_SERVICE_THREAD
9003: LeaveCriticalSection(&key_buf_crit_sect);
9004: #endif
9005: }
9006: }
9007:
9008: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID)
9009: {
9010: while(key_recv == 0 && !m_exit) {
9011: pcbios_update_key_code(true);
9012: }
9013: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
9014: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
9015: if(REG8(AH) == 0x10) {
9016: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
9017: } else {
9018: key_code = ((key_code >> 16) & 0xff00);
9019: }
9020: key_recv >>= 16;
9021: }
9022: }
9023: REG16(AX) = key_code & 0xffff;
9024: key_code >>= 16;
9025: key_recv >>= 16;
9026:
9027: #ifdef USE_SERVICE_THREAD
9028: service_exit = true;
9029: #endif
9030: return(0);
9031: }
9032:
9033: inline void pcbios_int_16h_00h()
9034: {
9035: #ifdef USE_SERVICE_THREAD
9036: if(!in_service && !in_service_29h) {
9037: start_service_loop(pcbios_int_16h_00h_thread);
9038: } else {
9039: #endif
9040: pcbios_int_16h_00h_thread(NULL);
9041: REQUEST_HARDWRE_UPDATE();
9042: #ifdef USE_SERVICE_THREAD
9043: }
9044: #endif
9045: }
9046:
9047: inline void pcbios_int_16h_01h()
9048: {
9049: if(key_recv == 0) {
9050: pcbios_update_key_code(false);
9051: }
9052: if(key_recv != 0) {
9053: UINT32 key_code_tmp = key_code;
9054: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
9055: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
9056: if(REG8(AH) == 0x11) {
9057: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
9058: } else {
9059: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
9060: }
9061: }
9062: }
9063: REG16(AX) = key_code_tmp & 0xffff;
9064: #if defined(HAS_I386)
9065: m_ZF = 0;
9066: #else
9067: m_ZeroVal = 1;
9068: #endif
9069: } else {
9070: #if defined(HAS_I386)
9071: m_ZF = 1;
9072: #else
9073: m_ZeroVal = 0;
9074: #endif
9075: }
9076: }
9077:
9078: inline void pcbios_int_16h_02h()
9079: {
9080: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
9081: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
9082: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
9083: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
9084: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
9085: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
9086: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
9087: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
9088: }
9089:
9090: inline void pcbios_int_16h_03h()
9091: {
9092: static UINT16 status = 0;
9093:
9094: switch(REG8(AL)) {
9095: case 0x05:
9096: status = REG16(BX);
9097: break;
9098: case 0x06:
9099: REG16(BX) = status;
9100: break;
9101: default:
9102: m_CF = 1;
9103: break;
9104: }
9105: }
9106:
9107: inline void pcbios_int_16h_05h()
9108: {
9109: if(key_buf_char != NULL && key_buf_scan != NULL) {
9110: #ifdef USE_SERVICE_THREAD
9111: EnterCriticalSection(&key_buf_crit_sect);
9112: #endif
9113: pcbios_set_key_buffer(REG8(CL), REG8(CH));
9114: #ifdef USE_SERVICE_THREAD
9115: LeaveCriticalSection(&key_buf_crit_sect);
9116: #endif
9117: }
9118: REG8(AL) = 0x00;
9119: }
9120:
9121: inline void pcbios_int_16h_09h()
9122: {
9123: REG8(AL) = 0x00;
9124: // REG8(AL) |= 0x01; // INT 16/AX=0300h supported (set default delay and rate (PCjr and some PS/2))
9125: // REG8(AL) |= 0x02; // INT 16/AX=0304h supported (turn off typematic repeat (PCjr and some PS/2))
9126: REG8(AL) |= 0x04; // INT 16/AX=0305h supported (set repeat rate and delay (AT,PS))
9127: REG8(AL) |= 0x08; // INT 16/AX=0306h supported (get current typematic rate and delay (newer PS/2s))
9128: REG8(AL) |= 0x10; // INT 16/AH=0Ah supported (get keyboard id)
9129: REG8(AL) |= 0x20; // INT 16/AH=10h-12h supported (enhanced keyboard support)
9130: // REG8(AL) |= 0x40; // INT 16/AH=20h-22h supported (122-key keyboard support)
9131: // REG8(AL) |= 0x80; // reserved
9132: }
9133:
9134: inline void pcbios_int_16h_0ah()
9135: {
9136: // REG16(BX) = 0x41ab; // MF2 Keyboard (usually in translate mode)
9137: REG16(BX) = 0x83ab; // MF2 Keyboard (pass-through mode)
9138: }
9139:
9140: inline void pcbios_int_16h_11h()
9141: {
9142: int key_char, key_scan;
9143:
9144: #ifdef USE_SERVICE_THREAD
9145: EnterCriticalSection(&key_buf_crit_sect);
9146: #endif
9147: if(pcbios_check_key_buffer(&key_char, &key_scan)) {
9148: REG8(AL) = key_char;
9149: REG8(AH) = key_scan;
9150: #if defined(HAS_I386)
9151: m_ZF = 0;
9152: #else
9153: m_ZeroVal = 1;
9154: #endif
9155: } else {
9156: #if defined(HAS_I386)
9157: m_ZF = 1;
9158: #else
9159: m_ZeroVal = 0;
9160: #endif
9161: }
9162: #ifdef USE_SERVICE_THREAD
9163: LeaveCriticalSection(&key_buf_crit_sect);
9164: #endif
9165: }
9166:
9167: inline void pcbios_int_16h_12h()
9168: {
9169: pcbios_int_16h_02h();
9170:
9171: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
9172: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
9173: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
9174: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
9175: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
9176: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
9177: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
9178: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
9179: }
9180:
9181: inline void pcbios_int_16h_13h()
9182: {
9183: static UINT16 status = 0;
9184:
9185: switch(REG8(AL)) {
9186: case 0x00:
9187: status = REG16(DX);
9188: break;
9189: case 0x01:
9190: REG16(DX) = status;
9191: break;
9192: default:
9193: 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));
9194: m_CF = 1;
9195: break;
9196: }
9197: }
9198:
9199: inline void pcbios_int_16h_14h()
9200: {
9201: static UINT8 status = 0;
9202:
9203: switch(REG8(AL)) {
9204: case 0x00:
9205: case 0x01:
9206: status = REG8(AL);
9207: break;
9208: case 0x02:
9209: REG8(AL) = status;
9210: break;
9211: default:
9212: 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));
9213: m_CF = 1;
9214: break;
9215: }
9216: }
9217:
9218: inline void pcbios_int_16h_55h()
9219: {
9220: switch(REG8(AL)) {
9221: case 0x00:
9222: // keyboard tsr is not present
9223: break;
9224: case 0xfe:
9225: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
9226: break;
9227: case 0xff:
9228: break;
9229: default:
9230: 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));
9231: m_CF = 1;
9232: break;
9233: }
9234: }
9235:
9236: inline void pcbios_int_16h_6fh()
9237: {
9238: switch(REG8(AL)) {
9239: case 0x00:
9240: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
9241: break;
9242: default:
9243: 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));
9244: m_CF = 1;
9245: break;
9246: }
9247: }
9248:
9249: UINT16 pcbios_printer_jis2sjis(UINT16 jis)
9250: {
9251: UINT8 hi = jis >> 8;
9252: UINT8 lo = jis & 0xff;
9253:
9254: lo = (hi & 0x01) ? lo - 0x1f : lo + 0x7d;
9255: hi = (hi - 0x21) / 2 + 0x81;
9256: hi = (hi >= 0xa0) ? hi + 0x40 : hi;
9257: lo = (lo >= 0x7f) ? lo + 0x01 : lo;
9258:
9259: return((hi << 8) + lo);
9260: }
9261:
9262: UINT16 pcbios_printer_sjis2jis(UINT16 sjis)
9263: {
9264: UINT8 hi = sjis >> 8;
9265: UINT8 lo = sjis & 0xff;
9266:
9267: if(hi == 0x80 || (hi >= 0xeb && hi <= 0xef) || (hi >= 0xf4 && hi <= 0xff)) {
9268: return(0x2121);
9269: }
9270: if((lo >= 0x00 && lo <= 0x3f) || lo == 0x7f || (lo >= 0xfd && lo <= 0xff)) {
9271: return(0x2121);
9272: }
9273: if(hi >= 0xf0 && hi <= 0xf3) {
9274: // gaiji
9275: if(lo >= 0x40 && lo <= 0x7e) {
9276: return(0x7721 + lo - 0x40 + (hi - 0xf0) * 0x200);
9277: }
9278: if(lo >= 0x80 && lo <= 0x9e) {
9279: return(0x7760 + lo - 0x80 + (hi - 0xf0) * 0x200);
9280: }
9281: if(lo >= 0x9f && lo <= 0xfc) {
9282: return(0x7821 + lo - 0x9f + (hi - 0xf0) * 0x200);
9283: }
9284: }
9285: hi = (hi >= 0xe0) ? hi - 0x40 : hi;
9286: lo = (lo >= 0x80) ? lo - 0x01 : lo;
9287: hi = ((lo >= 0x9e) ? 1 : 0) + (hi - 0x81) * 2 + 0x21;
9288: lo = ((lo >= 0x9e) ? lo - 0x9e : lo - 0x40) + 0x21;
9289:
9290: return((hi << 8) + lo);
9291: }
9292:
9293: // AX�e�N�j�J�����t�@�����X�K�C�h 1989
9294: // �t�^10 ���{��g��PRINTER DRIVER NIOS�T�d�l
9295: // 6. �R���g���[���R�[�h�̉��
9296:
9297: void pcbios_printer_out(int c, UINT8 data)
9298: {
9299: if(pio[c].conv_mode) {
9300: if(pio[c].sjis_hi != 0) {
9301: if(!pio[c].jis_mode) {
9302: printer_out(c, 0x1c);
9303: printer_out(c, 0x26);
9304: pio[c].jis_mode = true;
9305: }
9306: UINT16 jis = pcbios_printer_sjis2jis((pio[c].sjis_hi << 8) | data);
9307: printer_out(c, jis >> 8);
9308: printer_out(c, jis & 0xff);
9309: pio[c].sjis_hi = 0;
9310: } else if(pio[c].esc_buf[0] == 0x1b) {
9311: printer_out(c, data);
9312: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
9313: pio[c].esc_buf[pio[c].esc_len] = data;
9314: }
9315: pio[c].esc_len++;
9316:
9317: switch(pio[c].esc_buf[1]) {
9318: case 0x33: // 1Bh 33h XX
9319: case 0x4a: // 1Bh 4Ah XX
9320: case 0x4e: // 1Bh 4Eh XX
9321: case 0x51: // 1Bh 51h XX
9322: case 0x55: // 1Bh 55h XX
9323: case 0x6c: // 1Bh 6Ch XX
9324: case 0x71: // 1Bh 71h XX
9325: case 0x72: // 1Bh 72h XX
9326: if(pio[c].esc_len == 3) {
9327: pio[c].esc_buf[0] = 0x00;
9328: }
9329: break;
9330: case 0x24: // 1Bh 24h XX XX
9331: case 0x5c: // 1Bh 5Ch XX XX
9332: if(pio[c].esc_len == 4) {
9333: pio[c].esc_buf[0] = 0x00;
9334: }
9335: break;
9336: case 0x2a: // 1Bh 2Ah XX XX XX data
9337: if(pio[c].esc_len >= 3) {
9338: switch(pio[c].esc_buf[2]) {
9339: case 0: case 1: case 2: case 3: case 4: case 6:
9340: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 1) {
9341: pio[c].esc_buf[0] = 0x00;
9342: }
9343: break;
9344: case 32: case 33: case 38: case 39: case 40:
9345: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 3) {
9346: pio[c].esc_buf[0] = 0x00;
9347: }
9348: break;
9349: case 71: case 72: case 73:
9350: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 6) {
9351: pio[c].esc_buf[0] = 0x00;
9352: }
9353: break;
9354: default:
9355: pio[c].esc_buf[0] = 0x00;
9356: break;
9357: }
9358: }
9359: break;
9360: case 0x40: // 1Bh 40h
9361: if(pio[c].jis_mode) {
9362: printer_out(c, 0x1c);
9363: printer_out(c, 0x2e);
9364: pio[c].jis_mode = false;
9365: }
9366: pio[c].esc_buf[0] = 0x00;
9367: break;
9368: case 0x42: // 1Bh 42h data 00h
9369: case 0x44: // 1Bh 44h data 00h
9370: if(pio[c].esc_len >= 3 && data == 0) {
9371: pio[c].esc_buf[0] = 0x00;
9372: }
9373: break;
9374: case 0x43: // 1Bh 43h (00h) XX
9375: if(pio[c].esc_len >= 3 && data != 0) {
9376: pio[c].esc_buf[0] = 0x00;
9377: }
9378: break;
9379: default: // 1Bh XX
9380: pio[c].esc_buf[0] = 0x00;
9381: break;
9382: }
9383: } else if(pio[c].esc_buf[0] == 0x1c) {
9384: printer_out(c, data);
9385: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
9386: pio[c].esc_buf[pio[c].esc_len] = data;
9387: }
9388: pio[c].esc_len++;
9389:
9390: switch(pio[c].esc_buf[1]) {
9391: case 0x21: // 1Ch 21h XX
9392: case 0x2d: // 1Ch 2Dh XX
9393: case 0x57: // 1Ch 57h XX
9394: case 0x6b: // 1Ch 6Bh XX
9395: case 0x72: // 1Ch 72h XX
9396: case 0x78: // 1Ch 78h XX
9397: if(pio[c].esc_len == 3) {
9398: pio[c].esc_buf[0] = 0x00;
9399: }
9400: break;
9401: case 0x26: // 1Ch 26h
9402: pio[c].jis_mode = true;
9403: pio[c].esc_buf[0] = 0x00;
9404: break;
9405: case 0x2e: // 1Ch 2Eh
9406: pio[c].jis_mode = false;
9407: pio[c].esc_buf[0] = 0x00;
9408: break;
9409: case 0x32: // 1Ch 32h XX XX data
9410: if(pio[c].esc_len == 76) {
9411: pio[c].esc_buf[0] = 0x00;
9412: }
9413: break;
9414: case 0x44: // 1Bh 44h data 00h
9415: if(pio[c].esc_len == 6) {
9416: pio[c].esc_buf[0] = 0x00;
9417: }
9418: break;
9419: case 0x53: // 1Ch 53h XX XX
9420: case 0x54: // 1Ch 54h XX XX
9421: if(pio[c].esc_len == 4) {
9422: pio[c].esc_buf[0] = 0x00;
9423: }
9424: break;
9425: default: // 1Ch XX
9426: pio[c].esc_buf[0] = 0x00;
9427: break;
9428: }
9429: } else if(data == 0x1b || data == 0x1c) {
9430: printer_out(c, data);
9431: pio[c].esc_buf[0] = data;
9432: pio[c].esc_len = 1;
9433: } else if((data >= 0x80 && data <= 0x9f) || (data >= 0xe0 && data <= 0xff)) {
9434: pio[c].sjis_hi = data;
9435: } else {
9436: if(pio[c].jis_mode) {
9437: printer_out(c, 0x1c);
9438: printer_out(c, 0x2e);
9439: pio[c].jis_mode = false;
9440: }
9441: printer_out(c, data);
9442: }
9443: } else {
9444: if(pio[c].jis_mode) {
9445: printer_out(c, 0x1c);
9446: printer_out(c, 0x2e);
9447: pio[c].jis_mode = false;
9448: }
9449: printer_out(c, data);
9450: }
9451: }
9452:
9453: inline void pcbios_int_17h_00h()
9454: {
9455: if(REG16(DX) < 3) {
9456: pcbios_printer_out(REG16(DX), REG8(AL));
9457: REG8(AH) = 0xd0;
9458: }
9459: }
9460:
9461: inline void pcbios_int_17h_01h()
9462: {
9463: if(REG16(DX) < 3) {
9464: REG8(AH) = 0xd0;
9465: }
9466: }
9467:
9468: inline void pcbios_int_17h_02h()
9469: {
9470: if(REG16(DX) < 3) {
9471: REG8(AH) = 0xd0;
9472: }
9473: }
9474:
9475: inline void pcbios_int_17h_03h()
9476: {
9477: switch(REG8(AL)) {
9478: case 0x00:
9479: if(REG16(DX) < 3) {
9480: if(pio[REG16(DX)].jis_mode) {
9481: printer_out(REG16(DX), 0x1c);
9482: printer_out(REG16(DX), 0x2e);
9483: pio[REG16(DX)].jis_mode = false;
9484: }
9485: for(UINT16 i = 0; i < REG16(CX); i++) {
9486: printer_out(REG16(DX), mem[SREG_BASE(ES) + REG16(BX) + i]);
9487: }
9488: REG16(CX) = 0x0000;
9489: REG8(AH) = 0xd0;
9490: }
9491: break;
9492: default:
9493: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x17, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9494: break;
9495: }
9496: }
9497:
9498: inline void pcbios_int_17h_50h()
9499: {
9500: switch(REG8(AL)) {
9501: case 0x00:
9502: if(REG16(DX) < 3) {
9503: if(REG16(BX) = 0x0001) {
9504: pio[REG16(DX)].conv_mode = false;
9505: REG8(AL) = 0x00;
9506: } else if(REG16(BX) = 0x0051) {
9507: pio[REG16(DX)].conv_mode = true;
9508: REG8(AL) = 0x00;
9509: } else {
9510: REG8(AL) = 0x01;
9511: }
9512: } else {
9513: REG8(AL) = 0x02;
9514: }
9515: break;
9516: case 0x01:
9517: if(REG16(DX) < 3) {
9518: if(pio[REG16(DX)].conv_mode) {
9519: REG16(BX) = 0x0051;
9520: } else {
9521: REG16(BX) = 0x0001;
9522: }
9523: REG8(AL) = 0x00;
9524: } else {
9525: REG8(AL) = 0x02;
9526: }
9527: break;
9528: default:
9529: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x17, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9530: break;
9531: }
9532: }
9533:
9534: inline void pcbios_int_17h_51h()
9535: {
9536: if(REG8(DH) >= 0x21 && REG8(DH) <= 0x7e && REG8(DL) >= 0x21 && REG8(DL) <= 0x7e) {
9537: REG16(DX) = pcbios_printer_jis2sjis(REG16(DX));
9538: } else {
9539: REG16(DX) = 0x0000;
9540: }
9541: }
9542:
9543: inline void pcbios_int_17h_52h()
9544: {
9545: if(((REG8(DH) >= 0x81 && REG8(DH) <= 0x9f) || (REG8(DH) >= 0xe0 && REG8(DH) <= 0xfc)) && (REG8(DL) >= 0x40 && REG8(DL) <= 0xfc && REG8(DL) != 0x7f)) {
9546: REG16(DX) = pcbios_printer_sjis2jis(REG16(DX));
9547: } else {
9548: REG16(DX) = 0x0000;
9549: }
9550: }
9551:
9552: inline void pcbios_int_17h_84h()
9553: {
9554: if(REG16(DX) < 3) {
9555: if(pio[REG16(DX)].jis_mode) {
9556: printer_out(REG16(DX), 0x1c);
9557: printer_out(REG16(DX), 0x2e);
9558: pio[REG16(DX)].jis_mode = false;
9559: }
9560: printer_out(REG16(DX), REG8(AL));
9561: REG8(AH) = 0xd0;
9562: }
9563: }
9564:
9565: inline void pcbios_int_17h_85h()
9566: {
9567: pio[0].conv_mode = (REG8(AL) == 0x00);
9568: }
9569:
9570: inline void pcbios_int_1ah_00h()
9571: {
9572: pcbios_update_daily_timer_counter(timeGetTime());
9573: REG16(CX) = *(UINT16 *)(mem + 0x46e);
9574: REG16(DX) = *(UINT16 *)(mem + 0x46c);
9575: REG8(AL) = mem[0x470];
9576: mem[0x470] = 0;
9577: }
9578:
9579: inline int to_bcd(int t)
9580: {
9581: int u = (t % 100) / 10;
9582: return (u << 4) | (t % 10);
9583: }
9584:
9585: inline void pcbios_int_1ah_02h()
9586: {
9587: SYSTEMTIME time;
9588:
9589: GetLocalTime(&time);
9590: REG8(CH) = to_bcd(time.wHour);
9591: REG8(CL) = to_bcd(time.wMinute);
9592: REG8(DH) = to_bcd(time.wSecond);
9593: REG8(DL) = 0x00;
9594: }
9595:
9596: inline void pcbios_int_1ah_04h()
9597: {
9598: SYSTEMTIME time;
9599:
9600: GetLocalTime(&time);
9601: REG8(CH) = to_bcd(time.wYear / 100);
9602: REG8(CL) = to_bcd(time.wYear);
9603: REG8(DH) = to_bcd(time.wMonth);
9604: REG8(DL) = to_bcd(time.wDay);
9605: }
9606:
9607: inline void pcbios_int_1ah_0ah()
9608: {
9609: SYSTEMTIME time;
9610: FILETIME file_time;
9611: WORD dos_date, dos_time;
9612:
9613: GetLocalTime(&time);
9614: SystemTimeToFileTime(&time, &file_time);
9615: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
9616: REG16(CX) = dos_date;
9617: }
9618:
9619: // msdos system call
9620:
9621: inline void msdos_int_21h_56h(int lfn);
9622:
9623: inline void msdos_int_21h_00h()
9624: {
9625: msdos_process_terminate(SREG(CS), retval, 1);
9626: }
9627:
9628: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID)
9629: {
9630: REG8(AL) = msdos_getche();
9631: ctrl_break_detected = ctrl_break_pressed;
9632:
9633: #ifdef USE_SERVICE_THREAD
9634: service_exit = true;
9635: #endif
9636: return(0);
9637: }
9638:
9639: inline void msdos_int_21h_01h()
9640: {
9641: #ifdef USE_SERVICE_THREAD
9642: if(!in_service && !in_service_29h &&
9643: *(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) &&
9644: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
9645: // msdos_putch() will be used in this service
9646: // if int 29h is hooked, run this service in main thread to call int 29h
9647: start_service_loop(msdos_int_21h_01h_thread);
9648: } else {
9649: #endif
9650: msdos_int_21h_01h_thread(NULL);
9651: REQUEST_HARDWRE_UPDATE();
9652: #ifdef USE_SERVICE_THREAD
9653: }
9654: #endif
9655: }
9656:
9657: inline void msdos_int_21h_02h()
9658: {
9659: UINT8 data = REG8(DL);
9660: msdos_putch(data);
9661: REG8(AL) = data;
9662: ctrl_break_detected = ctrl_break_pressed;
9663: }
9664:
9665: inline void msdos_int_21h_03h()
9666: {
9667: REG8(AL) = msdos_aux_in();
9668: }
9669:
9670: inline void msdos_int_21h_04h()
9671: {
9672: msdos_aux_out(REG8(DL));
9673: }
9674:
9675: inline void msdos_int_21h_05h()
9676: {
9677: msdos_prn_out(REG8(DL));
9678: }
9679:
9680: inline void msdos_int_21h_06h()
9681: {
9682: if(REG8(DL) == 0xff) {
9683: if(msdos_kbhit()) {
9684: REG8(AL) = msdos_getch();
9685: #if defined(HAS_I386)
9686: m_ZF = 0;
9687: #else
9688: m_ZeroVal = 1;
9689: #endif
9690: } else {
9691: REG8(AL) = 0;
9692: #if defined(HAS_I386)
9693: m_ZF = 1;
9694: #else
9695: m_ZeroVal = 0;
9696: #endif
9697: maybe_idle();
9698: }
9699: } else {
9700: UINT8 data = REG8(DL);
9701: msdos_putch(data);
9702: REG8(AL) = data;
9703: }
9704: }
9705:
9706: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID)
9707: {
9708: REG8(AL) = msdos_getch();
9709:
9710: #ifdef USE_SERVICE_THREAD
9711: service_exit = true;
9712: #endif
9713: return(0);
9714: }
9715:
9716: inline void msdos_int_21h_07h()
9717: {
9718: #ifdef USE_SERVICE_THREAD
9719: if(!in_service && !in_service_29h) {
9720: start_service_loop(msdos_int_21h_07h_thread);
9721: } else {
9722: #endif
9723: msdos_int_21h_07h_thread(NULL);
9724: REQUEST_HARDWRE_UPDATE();
9725: #ifdef USE_SERVICE_THREAD
9726: }
9727: #endif
9728: }
9729:
9730: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID)
9731: {
9732: REG8(AL) = msdos_getch();
9733: ctrl_break_detected = ctrl_break_pressed;
9734:
9735: #ifdef USE_SERVICE_THREAD
9736: service_exit = true;
9737: #endif
9738: return(0);
9739: }
9740:
9741: inline void msdos_int_21h_08h()
9742: {
9743: #ifdef USE_SERVICE_THREAD
9744: if(!in_service && !in_service_29h) {
9745: start_service_loop(msdos_int_21h_08h_thread);
9746: } else {
9747: #endif
9748: msdos_int_21h_08h_thread(NULL);
9749: REQUEST_HARDWRE_UPDATE();
9750: #ifdef USE_SERVICE_THREAD
9751: }
9752: #endif
9753: }
9754:
9755: inline void msdos_int_21h_09h()
9756: {
9757: msdos_stdio_reopen();
9758:
9759: process_t *process = msdos_process_info_get(current_psp);
9760: int fd = msdos_psp_get_file_table(1, current_psp);
9761:
9762: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
9763: int len = 0;
9764:
9765: while(str[len] != '$' && len < 0x10000) {
9766: len++;
9767: }
9768: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
9769: // stdout is redirected to file
9770: msdos_write(fd, str, len);
9771: } else {
9772: for(int i = 0; i < len; i++) {
9773: msdos_putch(str[i]);
9774: }
9775: }
9776: REG8(AL) = '$';
9777: ctrl_break_detected = ctrl_break_pressed;
9778: }
9779:
9780: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID)
9781: {
9782: int ofs = SREG_BASE(DS) + REG16(DX);
9783: int max = mem[ofs] - 1;
9784: UINT8 *buf = mem + ofs + 2;
9785: int chr, p = 0;
9786:
9787: while((chr = msdos_getch()) != 0x0d) {
9788: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
9789: p = 0;
9790: msdos_putch(0x03);
9791: msdos_putch(0x0d);
9792: msdos_putch(0x0a);
9793: break;
9794: } else if(ctrl_break_pressed) {
9795: // skip this byte
9796: } else if(chr == 0x00) {
9797: // skip 2nd byte
9798: msdos_getch();
9799: } else if(chr == 0x08) {
9800: // back space
9801: if(p > 0) {
9802: p--;
9803: if(msdos_ctrl_code_check(buf[p])) {
9804: msdos_putch(0x08);
9805: msdos_putch(0x08);
9806: msdos_putch(0x20);
9807: msdos_putch(0x20);
9808: msdos_putch(0x08);
9809: msdos_putch(0x08);
9810: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
9811: p--;
9812: msdos_putch(0x08);
9813: msdos_putch(0x08);
9814: msdos_putch(0x20);
9815: msdos_putch(0x20);
9816: msdos_putch(0x08);
9817: msdos_putch(0x08);
9818: } else {
9819: msdos_putch(0x08);
9820: msdos_putch(0x20);
9821: msdos_putch(0x08);
9822: }
9823: }
9824: } else if(chr == 0x1b) {
9825: // escape
9826: while(p > 0) {
9827: p--;
9828: if(msdos_ctrl_code_check(buf[p])) {
9829: msdos_putch(0x08);
9830: msdos_putch(0x08);
9831: msdos_putch(0x20);
9832: msdos_putch(0x20);
9833: msdos_putch(0x08);
9834: msdos_putch(0x08);
9835: } else {
9836: msdos_putch(0x08);
9837: msdos_putch(0x20);
9838: msdos_putch(0x08);
9839: }
9840: }
9841: } else if(p < max) {
9842: buf[p++] = chr;
9843: msdos_putch(chr);
9844: }
9845: }
9846: buf[p] = 0x0d;
9847: msdos_putch(0x0d);
9848: mem[ofs + 1] = p;
9849: ctrl_break_detected = ctrl_break_pressed;
9850:
9851: #ifdef USE_SERVICE_THREAD
9852: service_exit = true;
9853: #endif
9854: return(0);
9855: }
9856:
9857: inline void msdos_int_21h_0ah()
9858: {
9859: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) {
9860: #ifdef USE_SERVICE_THREAD
9861: if(!in_service && !in_service_29h &&
9862: *(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) &&
9863: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
9864: // msdos_putch() will be used in this service
9865: // if int 29h is hooked, run this service in main thread to call int 29h
9866: start_service_loop(msdos_int_21h_0ah_thread);
9867: } else {
9868: #endif
9869: msdos_int_21h_0ah_thread(NULL);
9870: REQUEST_HARDWRE_UPDATE();
9871: #ifdef USE_SERVICE_THREAD
9872: }
9873: #endif
9874: }
9875: }
9876:
9877: inline void msdos_int_21h_0bh()
9878: {
9879: if(msdos_kbhit()) {
9880: REG8(AL) = 0xff;
9881: } else {
9882: REG8(AL) = 0x00;
9883: maybe_idle();
9884: }
9885: ctrl_break_detected = ctrl_break_pressed;
9886: }
9887:
9888: inline void msdos_int_21h_0ch()
9889: {
9890: // clear key buffer
9891: msdos_stdio_reopen();
9892:
9893: process_t *process = msdos_process_info_get(current_psp);
9894: int fd = msdos_psp_get_file_table(0, current_psp);
9895:
9896: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
9897: // stdin is redirected to file
9898: } else {
9899: while(msdos_kbhit()) {
9900: msdos_getch();
9901: }
9902: }
9903:
9904: switch(REG8(AL)) {
9905: case 0x01:
9906: msdos_int_21h_01h();
9907: break;
9908: case 0x06:
9909: msdos_int_21h_06h();
9910: break;
9911: case 0x07:
9912: msdos_int_21h_07h();
9913: break;
9914: case 0x08:
9915: msdos_int_21h_08h();
9916: break;
9917: case 0x0a:
9918: msdos_int_21h_0ah();
9919: break;
9920: default:
9921: // the buffer is flushed but no input is attempted
9922: break;
9923: }
9924: }
9925:
9926: inline void msdos_int_21h_0dh()
9927: {
9928: }
9929:
9930: inline void msdos_int_21h_0eh()
9931: {
9932: if(REG8(DL) < 26) {
9933: _chdrive(REG8(DL) + 1);
9934: msdos_cds_update(REG8(DL));
9935: msdos_sda_update(current_psp);
9936: }
9937: REG8(AL) = 26; // zdrive
9938: }
9939:
9940: inline void msdos_int_21h_0fh()
9941: {
9942: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9943: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9944: const char *path = msdos_fcb_path(fcb);
9945: HANDLE hFile = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9946:
9947: if(hFile == INVALID_HANDLE_VALUE) {
9948: REG8(AL) = 0xff;
9949: } else {
9950: REG8(AL) = 0;
9951: fcb->current_block = 0;
9952: fcb->record_size = 128;
9953: fcb->file_size = GetFileSize(hFile, NULL);
9954: fcb->handle = hFile;
9955: }
9956: }
9957:
9958: inline void msdos_int_21h_10h()
9959: {
9960: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9961: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9962:
9963: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
9964: }
9965:
9966: inline void msdos_int_21h_11h()
9967: {
9968: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9969: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
9970:
9971: process_t *process = msdos_process_info_get(current_psp);
9972: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9973: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
9974: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
9975: const char *path = msdos_fcb_path(fcb);
9976: WIN32_FIND_DATAA fd;
9977:
9978: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
9979: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9980: FindClose(dtainfo->find_handle);
9981: dtainfo->find_handle = INVALID_HANDLE_VALUE;
9982: }
9983: strcpy(process->volume_label, msdos_volume_label(path));
9984: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
9985: bool label_only = (dtainfo->allowable_mask == 8);
9986:
9987: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
9988: dtainfo->allowable_mask &= ~8;
9989: }
9990: if(!label_only && (dtainfo->find_handle = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) {
9991: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
9992: !msdos_find_file_has_8dot3name(&fd)) {
9993: if(!FindNextFileA(dtainfo->find_handle, &fd)) {
9994: FindClose(dtainfo->find_handle);
9995: dtainfo->find_handle = INVALID_HANDLE_VALUE;
9996: break;
9997: }
9998: }
9999: }
10000: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10001: if(ext_fcb->flag == 0xff) {
10002: ext_find->flag = 0xff;
10003: memset(ext_find->reserved, 0, 5);
10004: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
10005: }
10006: find->drive = _getdrive();
10007: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
10008: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
10009: find->nt_res = 0;
10010: msdos_find_file_conv_local_time(&fd);
10011: find->create_time_ms = 0;
10012: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
10013: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
10014: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
10015: find->cluster_hi = find->cluster_lo = 0;
10016: find->file_size = fd.nFileSizeLow;
10017: REG8(AL) = 0x00;
10018: } else if(dtainfo->allowable_mask & 8) {
10019: if(ext_fcb->flag == 0xff) {
10020: ext_find->flag = 0xff;
10021: memset(ext_find->reserved, 0, 5);
10022: ext_find->attribute = 8;
10023: }
10024: find->drive = _getdrive();
10025: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
10026: find->attribute = 8;
10027: find->nt_res = 0;
10028: msdos_find_file_conv_local_time(&fd);
10029: find->create_time_ms = 0;
10030: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
10031: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
10032: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
10033: find->cluster_hi = find->cluster_lo = 0;
10034: find->file_size = 0;
10035: dtainfo->allowable_mask &= ~8;
10036: REG8(AL) = 0x00;
10037: } else {
10038: REG8(AL) = 0xff;
10039: }
10040: }
10041:
10042: inline void msdos_int_21h_12h()
10043: {
10044: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10045: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
10046:
10047: process_t *process = msdos_process_info_get(current_psp);
10048: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10049: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
10050: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
10051: WIN32_FIND_DATAA fd;
10052:
10053: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
10054: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10055: if(FindNextFileA(dtainfo->find_handle, &fd)) {
10056: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
10057: !msdos_find_file_has_8dot3name(&fd)) {
10058: if(!FindNextFileA(dtainfo->find_handle, &fd)) {
10059: FindClose(dtainfo->find_handle);
10060: dtainfo->find_handle = INVALID_HANDLE_VALUE;
10061: break;
10062: }
10063: }
10064: } else {
10065: FindClose(dtainfo->find_handle);
10066: dtainfo->find_handle = INVALID_HANDLE_VALUE;
10067: }
10068: }
10069: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10070: if(ext_fcb->flag == 0xff) {
10071: ext_find->flag = 0xff;
10072: memset(ext_find->reserved, 0, 5);
10073: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
10074: }
10075: find->drive = _getdrive();
10076: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
10077: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
10078: find->nt_res = 0;
10079: msdos_find_file_conv_local_time(&fd);
10080: find->create_time_ms = 0;
10081: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
10082: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
10083: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
10084: find->cluster_hi = find->cluster_lo = 0;
10085: find->file_size = fd.nFileSizeLow;
10086: REG8(AL) = 0x00;
10087: } else if(dtainfo->allowable_mask & 8) {
10088: if(ext_fcb->flag == 0xff) {
10089: ext_find->flag = 0xff;
10090: memset(ext_find->reserved, 0, 5);
10091: ext_find->attribute = 8;
10092: }
10093: find->drive = _getdrive();
10094: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
10095: find->attribute = 8;
10096: find->nt_res = 0;
10097: msdos_find_file_conv_local_time(&fd);
10098: find->create_time_ms = 0;
10099: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
10100: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
10101: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
10102: find->cluster_hi = find->cluster_lo = 0;
10103: find->file_size = 0;
10104: dtainfo->allowable_mask &= ~8;
10105: REG8(AL) = 0x00;
10106: } else {
10107: REG8(AL) = 0xff;
10108: }
10109: }
10110:
10111: inline void msdos_int_21h_13h()
10112: {
10113: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
10114: REG8(AL) = 0xff;
10115: } else {
10116: REG8(AL) = 0x00;
10117: }
10118: }
10119:
10120: inline void msdos_int_21h_14h()
10121: {
10122: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10123: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10124: process_t *process = msdos_process_info_get(current_psp);
10125: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10126: DWORD num = 0;
10127:
10128: memset(mem + dta_laddr, 0, fcb->record_size);
10129: SetFilePointer(fcb->handle, fcb->record_size * (fcb->current_block * 128 + fcb->cur_record), NULL, FILE_BEGIN);
10130:
10131: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
10132: REG8(AL) = 1;
10133: } else {
10134: if(++fcb->cur_record >= 128) {
10135: fcb->current_block += fcb->cur_record / 128;
10136: fcb->cur_record %= 128;
10137: }
10138: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
10139: }
10140: }
10141:
10142: inline void msdos_int_21h_15h()
10143: {
10144: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10145: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10146: process_t *process = msdos_process_info_get(current_psp);
10147: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10148: DWORD num = 0;
10149:
10150: SetFilePointer(fcb->handle, fcb->record_size * (fcb->current_block * 128 + fcb->cur_record), NULL, FILE_BEGIN);
10151: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
10152: fcb->file_size = GetFileSize(fcb->handle, NULL);
10153:
10154: if(num != fcb->record_size) {
10155: REG8(AL) = 1;
10156: } else {
10157: if(++fcb->cur_record >= 128) {
10158: fcb->current_block += fcb->cur_record / 128;
10159: fcb->cur_record %= 128;
10160: }
10161: REG8(AL) = 0;
10162: }
10163: }
10164:
10165: inline void msdos_int_21h_16h()
10166: {
10167: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10168: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10169: const char *path = msdos_fcb_path(fcb);
10170: HANDLE hFile = CreateFileA(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, ext_fcb->flag == 0xff ? ext_fcb->attribute : FILE_ATTRIBUTE_NORMAL, NULL);
10171:
10172: if(hFile == INVALID_HANDLE_VALUE) {
10173: REG8(AL) = 0xff;
10174: } else {
10175: REG8(AL) = 0;
10176: fcb->current_block = 0;
10177: fcb->record_size = 128;
10178: fcb->file_size = 0;
10179: fcb->handle = hFile;
10180: }
10181: }
10182:
10183: inline void msdos_int_21h_17h()
10184: {
10185: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10186: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
10187: // const char *path_src = msdos_fcb_path(fcb_src);
10188: char path_src[MAX_PATH];
10189: strcpy(path_src, msdos_fcb_path(fcb_src));
10190:
10191: fcb_t *fcb_dst = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16 + (ext_fcb_src->flag == 0xff ? 7 : 0));
10192: // const char *path_dst = msdos_fcb_path(fcb_dst);
10193: char path_dst[MAX_PATH];
10194: strcpy(path_dst, msdos_fcb_path(fcb_dst));
10195:
10196: if(rename(path_src, path_dst)) {
10197: REG8(AL) = 0xff;
10198: } else {
10199: REG8(AL) = 0;
10200: }
10201: }
10202:
10203: inline void msdos_int_21h_18h()
10204: {
10205: REG8(AL) = 0x00;
10206: }
10207:
10208: inline void msdos_int_21h_19h()
10209: {
10210: REG8(AL) = _getdrive() - 1;
10211: }
10212:
10213: inline void msdos_int_21h_1ah()
10214: {
10215: process_t *process = msdos_process_info_get(current_psp);
10216:
10217: process->dta.w.l = REG16(DX);
10218: process->dta.w.h = SREG(DS);
10219: msdos_sda_update(current_psp);
10220: }
10221:
10222: inline void msdos_int_21h_1bh()
10223: {
10224: int drive_num = _getdrive() - 1;
10225: UINT16 seg, ofs;
10226:
10227: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
10228: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
10229: REG8(AL) = dpb->highest_sector_num + 1;
10230: REG16(CX) = dpb->bytes_per_sector;
10231: REG16(DX) = dpb->highest_cluster_num - 1;
10232: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
10233: } else {
10234: REG8(AL) = 0xff;
10235: m_CF = 1;
10236: }
10237:
10238: }
10239:
10240: inline void msdos_int_21h_1ch()
10241: {
10242: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
10243: UINT16 seg, ofs;
10244:
10245: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
10246: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
10247: REG8(AL) = dpb->highest_sector_num + 1;
10248: REG16(CX) = dpb->bytes_per_sector;
10249: REG16(DX) = dpb->highest_cluster_num - 1;
10250: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
10251: } else {
10252: REG8(AL) = 0xff;
10253: m_CF = 1;
10254: }
10255:
10256: }
10257:
10258: inline void msdos_int_21h_1dh()
10259: {
10260: REG8(AL) = 0;
10261: }
10262:
10263: inline void msdos_int_21h_1eh()
10264: {
10265: REG8(AL) = 0;
10266: }
10267:
10268: inline void msdos_int_21h_1fh()
10269: {
10270: int drive_num = _getdrive() - 1;
10271: UINT16 seg, ofs;
10272:
10273: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
10274: REG8(AL) = 0;
10275: SREG(DS) = seg;
10276: i386_load_segment_descriptor(DS);
10277: REG16(BX) = ofs;
10278: } else {
10279: REG8(AL) = 0xff;
10280: m_CF = 1;
10281: }
10282: }
10283:
10284: inline void msdos_int_21h_20h()
10285: {
10286: REG8(AL) = 0;
10287: }
10288:
10289: inline void msdos_int_21h_21h()
10290: {
10291: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10292: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10293: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record;
10294:
10295: fcb->current_block = rec / 128;
10296: fcb->cur_record = rec % 128;
10297:
10298: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
10299: REG8(AL) = 1;
10300: } else {
10301: process_t *process = msdos_process_info_get(current_psp);
10302: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10303: memset(mem + dta_laddr, 0, fcb->record_size);
10304: DWORD num = 0;
10305: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
10306: REG8(AL) = 1;
10307: } else {
10308: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
10309: }
10310: }
10311: }
10312:
10313: inline void msdos_int_21h_22h()
10314: {
10315: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10316: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10317: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record;
10318:
10319: fcb->current_block = rec / 128;
10320: fcb->cur_record = rec % 128;
10321:
10322: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
10323: REG8(AL) = 1;
10324: } else {
10325: process_t *process = msdos_process_info_get(current_psp);
10326: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10327: DWORD num = 0;
10328: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
10329: fcb->file_size = GetFileSize(fcb->handle, NULL);
10330: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
10331: }
10332: }
10333:
10334: inline void msdos_int_21h_23h()
10335: {
10336: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10337: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10338: const char *path = msdos_fcb_path(fcb);
10339: HANDLE hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10340:
10341: if(hFile == INVALID_HANDLE_VALUE) {
10342: REG8(AL) = 0xff;
10343: } else {
10344: UINT32 size = GetFileSize(hFile, NULL);
10345: UINT32 rec = size / fcb->record_size + ((size % fcb->record_size) != 0);
10346: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec;
10347: CloseHandle(hFile);
10348: REG8(AL) = 0;
10349: }
10350: }
10351:
10352: inline void msdos_int_21h_24h()
10353: {
10354: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10355: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10356: UINT32 rec = fcb->current_block * 128 + fcb->cur_record;
10357:
10358: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec;
10359: }
10360:
10361: inline void msdos_int_21h_25h()
10362: {
10363: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
10364: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
10365: }
10366:
10367: inline void msdos_int_21h_26h()
10368: {
10369: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
10370:
10371: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
10372: psp->first_mcb = REG16(DX) + (PSP_SIZE >> 4);
10373: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
10374: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
10375: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
10376: psp->parent_psp = 0;
10377: }
10378:
10379: inline void msdos_int_21h_27h()
10380: {
10381: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10382: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10383: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record;
10384:
10385: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
10386: REG8(AL) = 1;
10387: } else if(REG16(CX) == 0) {
10388: REG8(AL) = 0;
10389: } else {
10390: process_t *process = msdos_process_info_get(current_psp);
10391: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10392: UINT32 len = fcb->record_size * REG16(CX);
10393: memset(mem + dta_laddr, 0, len);
10394: DWORD num = 0;
10395: if(!ReadFile(fcb->handle, mem + dta_laddr, len, &num, NULL) || num == 0) {
10396: REG8(AL) = 1;
10397: } else {
10398: UINT16 nrec = num / fcb->record_size + ((num % fcb->record_size) != 0);
10399: rec += nrec;
10400: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec;
10401: REG8(AL) = (num == len) ? 0 : 3;
10402: REG16(CX) = nrec;
10403: }
10404: }
10405: fcb->current_block = rec / 128;
10406: fcb->cur_record = rec % 128;
10407: }
10408:
10409: inline void msdos_int_21h_28h()
10410: {
10411: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
10412: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
10413: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record;
10414:
10415: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
10416: REG8(AL) = 1;
10417: } else if(REG16(CX) == 0) {
10418: if(!SetEndOfFile(fcb->handle)) {
10419: REG8(AL) = 1;
10420: } else {
10421: fcb->file_size = GetFileSize(fcb->handle, NULL);
10422: REG8(AL) = 0;
10423: }
10424: } else {
10425: process_t *process = msdos_process_info_get(current_psp);
10426: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10427: UINT32 len = fcb->record_size * REG16(CX);
10428: DWORD num = 0;
10429: WriteFile(fcb->handle, mem + dta_laddr, len, &num, NULL);
10430: fcb->file_size = GetFileSize(fcb->handle, NULL);
10431: UINT16 nrec = num / fcb->record_size + ((num % fcb->record_size) != 0);
10432: rec += nrec;
10433: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec;
10434: REG8(AL) = (num == len) ? 0 : 1;
10435: REG16(CX) = nrec;
10436: }
10437: fcb->current_block = rec / 128;
10438: fcb->cur_record = rec % 128;
10439: }
10440:
10441: inline void msdos_int_21h_29h()
10442: {
10443: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
10444: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
10445: UINT8 drv = 0;
10446: char sep_chars[] = ":.;,=+";
10447: char end_chars[] = "\\<>|/\"[]";
10448: char spc_chars[] = " \t";
10449:
10450: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
10451: buffer[1023] = 0;
10452: memset(name, 0x20, sizeof(name));
10453: memset(ext, 0x20, sizeof(ext));
10454:
10455: if(REG8(AL) & 1) {
10456: ofs += strspn((char *)(buffer + ofs), spc_chars);
10457: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
10458: ofs++;
10459: }
10460: }
10461: ofs += strspn((char *)(buffer + ofs), spc_chars);
10462:
10463: if(buffer[ofs + 1] == ':') {
10464: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
10465: drv = buffer[ofs] - 'a' + 1;
10466: ofs += 2;
10467: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
10468: ofs++;
10469: }
10470: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
10471: drv = buffer[ofs] - 'A' + 1;
10472: ofs += 2;
10473: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
10474: ofs++;
10475: }
10476: }
10477: }
10478: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
10479: UINT8 c = buffer[ofs];
10480: if(is_kanji) {
10481: is_kanji = 0;
10482: } else if(msdos_lead_byte_check(c)) {
10483: is_kanji = 1;
10484: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
10485: break;
10486: } else if(c >= 'a' && c <= 'z') {
10487: c -= 0x20;
10488: }
10489: ofs++;
10490: name[i] = c;
10491: }
10492: if(buffer[ofs] == '.') {
10493: ofs++;
10494: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
10495: UINT8 c = buffer[ofs];
10496: if(is_kanji) {
10497: is_kanji = 0;
10498: } else if(msdos_lead_byte_check(c)) {
10499: is_kanji = 1;
10500: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
10501: break;
10502: } else if(c >= 'a' && c <= 'z') {
10503: c -= 0x20;
10504: }
10505: ofs++;
10506: ext[i] = c;
10507: }
10508: }
10509: int si = REG16(SI) + ofs;
10510: int ds = SREG(DS);
10511: while(si > 0xffff) {
10512: si -= 0x10;
10513: ds++;
10514: }
10515: REG16(SI) = si;
10516: SREG(DS) = ds;
10517: i386_load_segment_descriptor(DS);
10518:
10519: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
10520: if(!(REG8(AL) & 2) || drv != 0) {
10521: fcb[0] = drv;
10522: }
10523: if(!(REG8(AL) & 4) || name[0] != 0x20) {
10524: memcpy(fcb + 1, name, 8);
10525: }
10526: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
10527: memcpy(fcb + 9, ext, 3);
10528: }
10529: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
10530: if(fcb[i] == '*') {
10531: found_star = 1;
10532: }
10533: if(found_star) {
10534: fcb[i] = '?';
10535: }
10536: }
10537: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
10538: if(fcb[i] == '*') {
10539: found_star = 1;
10540: }
10541: if(found_star) {
10542: fcb[i] = '?';
10543: }
10544: }
10545:
10546: if(drv == 0 || msdos_is_valid_drive(drv - 1)) {
10547: if(memchr(fcb + 1, '?', 8 + 3)) {
10548: REG8(AL) = 0x01;
10549: } else {
10550: REG8(AL) = 0x00;
10551: }
10552: } else {
10553: REG8(AL) = 0xff;
10554: }
10555: }
10556:
10557: inline void msdos_int_21h_2ah()
10558: {
10559: SYSTEMTIME sTime;
10560:
10561: GetLocalTime(&sTime);
10562: REG16(CX) = sTime.wYear;
10563: REG8(DH) = (UINT8)sTime.wMonth;
10564: REG8(DL) = (UINT8)sTime.wDay;
10565: REG8(AL) = (UINT8)sTime.wDayOfWeek;
10566: }
10567:
10568: inline void msdos_int_21h_2bh()
10569: {
10570: REG8(AL) = 0xff;
10571: }
10572:
10573: inline void msdos_int_21h_2ch()
10574: {
10575: SYSTEMTIME sTime;
10576:
10577: GetLocalTime(&sTime);
10578: REG8(CH) = (UINT8)sTime.wHour;
10579: REG8(CL) = (UINT8)sTime.wMinute;
10580: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.68! root 10581: REG8(DL) = (UINT8)(sTime.wMilliseconds / 10);
1.1.1.67 root 10582: }
10583:
10584: inline void msdos_int_21h_2dh()
10585: {
10586: REG8(AL) = 0x00;
10587: }
10588:
10589: inline void msdos_int_21h_2eh()
10590: {
10591: process_t *process = msdos_process_info_get(current_psp);
10592:
10593: process->verify = REG8(AL);
10594: }
10595:
10596: inline void msdos_int_21h_2fh()
10597: {
10598: process_t *process = msdos_process_info_get(current_psp);
10599:
10600: REG16(BX) = process->dta.w.l;
10601: SREG(ES) = process->dta.w.h;
10602: i386_load_segment_descriptor(ES);
10603: }
10604:
10605: inline void msdos_int_21h_30h()
10606: {
10607: // Version Flag / OEM
10608: if(REG8(AL) == 0x01) {
10609: #ifdef SUPPORT_HMA
10610: REG16(BX) = 0x0000;
10611: #else
10612: REG16(BX) = 0x1000; // DOS is in HMA
10613: #endif
10614: } else {
10615: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
10616: // but this is not correct on Windows 98 SE
10617: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
10618: REG16(BX) = 0xff00; // OEM = Microsoft
10619: }
10620: REG16(CX) = 0x0000;
10621: REG8(AL) = dos_major_version; // 7
10622: REG8(AH) = dos_minor_version; // 10
10623: }
10624:
10625: inline void msdos_int_21h_31h()
10626: {
10627: try {
10628: msdos_mem_realloc(current_psp, REG16(DX), NULL);
10629: } catch(...) {
10630: // recover the broken mcb
10631: int mcb_seg = current_psp - 1;
10632: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
10633:
10634: if(mcb_seg < (MEMORY_END >> 4)) {
10635: mcb->mz = 'M';
10636: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
10637:
10638: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
10639: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
10640: } else {
10641: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
10642: }
10643: } else {
10644: mcb->mz = 'Z';
10645: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
10646: }
10647: msdos_mem_realloc(current_psp, REG16(DX), NULL);
10648: }
10649: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
10650: }
10651:
10652: inline void msdos_int_21h_32h()
10653: {
10654: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
10655: UINT16 seg, ofs;
10656:
10657: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
10658: REG8(AL) = 0;
10659: SREG(DS) = seg;
10660: i386_load_segment_descriptor(DS);
10661: REG16(BX) = ofs;
10662: } else {
10663: REG8(AL) = 0xff;
10664: m_CF = 1;
10665: }
10666: }
10667:
10668: inline void msdos_int_21h_33h()
10669: {
10670: char path[MAX_PATH];
10671: char drive = 3; // C:
10672:
10673: switch(REG8(AL)) {
10674: case 0x00:
10675: REG8(DL) = ctrl_break_checking;
10676: break;
10677: case 0x01:
10678: ctrl_break_checking = REG8(DL);
10679: break;
10680: case 0x02:
10681: {
10682: UINT8 old = ctrl_break_checking;
10683: ctrl_break_checking = REG8(DL);
10684: REG8(DL) = old;
10685: }
10686: break;
10687: case 0x03:
10688: case 0x04:
10689: // DOS 4.0+ - Unused
10690: break;
10691: case 0x05:
10692: if(GetSystemDirectoryA(path, MAX_PATH) != 0) {
10693: if(path[0] >= 'a' && path[0] <= 'z') {
10694: drive = path[0] - 'a' + 1;
10695: } else if(path[0] >= 'A' && path[0] <= 'Z') {
10696: drive = path[0] - 'A' + 1;
10697: }
10698: }
10699: REG8(DL) = (UINT8)drive;
10700: break;
10701: case 0x06:
10702: // MS-DOS version (7.10)
10703: REG8(BL) = 7;
10704: REG8(BH) = 10;
10705: REG8(DL) = 0;
10706: #ifdef SUPPORT_HMA
10707: REG8(DH) = 0x00;
10708: #else
10709: REG8(DH) = 0x10; // DOS is in HMA
10710: #endif
10711: break;
10712: case 0x07:
10713: if(REG8(DL) == 0) {
10714: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
10715: } else if(REG8(DL) == 1) {
10716: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
10717: }
10718: break;
10719: default:
10720: 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));
10721: // REG16(AX) = 0x01;
10722: // m_CF = 1;
10723: REG8(AL) = 0xff;
10724: break;
10725: }
10726: }
10727:
10728: inline void msdos_int_21h_34h()
10729: {
10730: SREG(ES) = SDA_TOP >> 4;
10731: i386_load_segment_descriptor(ES);
10732: REG16(BX) = offsetof(sda_t, indos_flag);
10733: }
10734:
10735: inline void msdos_int_21h_35h()
10736: {
10737: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
10738: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
10739: i386_load_segment_descriptor(ES);
10740: }
10741:
10742: inline void msdos_int_21h_36h()
10743: {
10744: struct _diskfree_t df = {0};
10745:
10746: if(_getdiskfree(REG8(DL), &df) == 0) {
10747: REG16(AX) = (UINT16)df.sectors_per_cluster;
10748: REG16(CX) = (UINT16)df.bytes_per_sector;
10749: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
10750: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
10751: } else {
10752: REG16(AX) = 0xffff;
10753: }
10754: }
10755:
10756: inline void msdos_int_21h_37h()
10757: {
10758: static UINT8 dev_flag = 0xff;
10759:
10760: switch(REG8(AL)) {
10761: case 0x00:
10762: {
10763: process_t *process = msdos_process_info_get(current_psp);
10764: REG8(AL) = 0x00;
10765: REG8(DL) = process->switchar;
10766: }
10767: break;
10768: case 0x01:
10769: {
10770: process_t *process = msdos_process_info_get(current_psp);
10771: REG8(AL) = 0x00;
10772: process->switchar = REG8(DL);
10773: msdos_sda_update(current_psp);
10774: }
10775: break;
10776: case 0x02:
10777: REG8(DL) = dev_flag;
10778: break;
10779: case 0x03:
10780: dev_flag = REG8(DL);
10781: break;
10782: case 0xd0:
10783: case 0xd1:
10784: case 0xd2:
10785: case 0xd3:
10786: case 0xd4:
10787: case 0xd5:
10788: case 0xd6:
10789: case 0xd7:
10790: case 0xdc:
10791: case 0xdd:
10792: case 0xde:
10793: case 0xdf:
10794: // DIET v1.43e
10795: // REG16(AX) = 1;
10796: REG8(AL) = 0xff;
10797: break;
10798: default:
10799: 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));
10800: // REG16(AX) = 1;
10801: REG8(AL) = 0xff;
10802: break;
10803: }
10804: }
10805:
10806: int get_country_info(country_info_t *ci, LCID locale = LOCALE_USER_DEFAULT)
10807: {
10808: char LCdata[80];
10809:
10810: ZeroMemory(ci, offsetof(country_info_t, reserved));
10811: GetLocaleInfoA(locale, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
10812: ci->currency_dec_digits = atoi(LCdata);
10813: GetLocaleInfoA(locale, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
10814: ci->currency_format = *LCdata - '0';
10815: GetLocaleInfoA(locale, LOCALE_IDATE, LCdata, sizeof(LCdata));
10816: ci->date_format = *LCdata - '0';
10817: GetLocaleInfoA(locale, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
10818: memcpy(&ci->currency_symbol, LCdata, 4);
10819: GetLocaleInfoA(locale, LOCALE_SDATE, LCdata, sizeof(LCdata));
10820: *ci->date_sep = *LCdata;
10821: GetLocaleInfoA(locale, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
10822: *ci->dec_sep = *LCdata;
10823: GetLocaleInfoA(locale, LOCALE_SLIST, LCdata, sizeof(LCdata));
10824: *ci->list_sep = *LCdata;
10825: GetLocaleInfoA(locale, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
10826: *ci->thou_sep = *LCdata;
10827: GetLocaleInfoA(locale, LOCALE_STIME, LCdata, sizeof(LCdata));
10828: *ci->time_sep = *LCdata;
10829: GetLocaleInfoA(locale, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
10830: if(strchr(LCdata, 'H') != NULL) {
10831: ci->time_format = 1;
10832: }
10833: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffc:000a
10834: ci->case_map.w.h = DUMMY_TOP >> 4;
10835: GetLocaleInfoA(locale, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
10836: return atoi(LCdata);
10837: }
10838:
10839: int get_country_info(country_info_t *ci, USHORT usPrimaryLanguage, USHORT usSubLanguage)
10840: {
10841: return get_country_info(ci, MAKELCID(MAKELANGID(usPrimaryLanguage, usSubLanguage), SORT_DEFAULT));
10842: }
10843:
10844: void set_country_info(country_info_t *ci, int size)
10845: {
10846: char LCdata[80];
10847:
10848: if(size >= 0x00 + 2) {
10849: memset(LCdata, 0, sizeof(LCdata));
10850: *LCdata = '0' + ci->date_format;
10851: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata);
10852: }
10853: if(size >= 0x02 + 5) {
10854: memset(LCdata, 0, sizeof(LCdata));
10855: memcpy(LCdata, &ci->currency_symbol, 4);
10856: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata);
10857: }
10858: if(size >= 0x07 + 2) {
10859: memset(LCdata, 0, sizeof(LCdata));
10860: *LCdata = *ci->thou_sep;
10861: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata);
10862: }
10863: if(size >= 0x09 + 2) {
10864: memset(LCdata, 0, sizeof(LCdata));
10865: *LCdata = *ci->dec_sep;
10866: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata);
10867: }
10868: if(size >= 0x0b + 2) {
10869: memset(LCdata, 0, sizeof(LCdata));
10870: *LCdata = *ci->date_sep;
10871: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata);
10872: }
10873: if(size >= 0x0d + 2) {
10874: memset(LCdata, 0, sizeof(LCdata));
10875: *LCdata = *ci->time_sep;
10876: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata);
10877: }
10878: if(size >= 0x0f + 1) {
10879: memset(LCdata, 0, sizeof(LCdata));
10880: *LCdata = '0' + ci->currency_format;
10881: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata);
10882: }
10883: if(size >= 0x10 + 1) {
10884: sprintf(LCdata, "%d", ci->currency_dec_digits);
10885: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata);
10886: }
10887: if(size >= 0x11 + 1) {
10888: // FIXME: is time format always H/h:mm:ss ???
10889: if(ci->time_format & 1) {
10890: sprintf(LCdata, "H%cmm%css", *ci->time_sep, *ci->time_sep);
10891: } else {
10892: sprintf(LCdata, "h%cmm%css", *ci->time_sep, *ci->time_sep);
10893: }
10894: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata);
10895: }
10896: if(size >= 0x12 + 4) {
10897: // 12h DWORD address of case map routine
10898: // (FAR CALL, AL = character to map to upper case [>= 80h])
10899: }
10900: if(size >= 0x16 + 2) {
10901: memset(LCdata, 0, sizeof(LCdata));
10902: *LCdata = *ci->list_sep;
10903: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata);
10904: }
10905: }
10906:
10907: #ifndef SUBLANG_SWAHILI
10908: #define SUBLANG_SWAHILI 0x01
10909: #endif
10910: #ifndef SUBLANG_TSWANA_BOTSWANA
10911: #define SUBLANG_TSWANA_BOTSWANA 0x02
10912: #endif
10913: #ifndef SUBLANG_LITHUANIAN_LITHUANIA
10914: #define SUBLANG_LITHUANIAN_LITHUANIA 0x01
10915: #endif
10916: #ifndef LANG_BANGLA
10917: #define LANG_BANGLA 0x45
10918: #endif
10919: #ifndef SUBLANG_BANGLA_BANGLADESH
10920: #define SUBLANG_BANGLA_BANGLADESH 0x02
10921: #endif
10922:
10923: static const struct {
10924: int code;
10925: USHORT usPrimaryLanguage;
10926: USHORT usSubLanguage;
10927: } country_table[] = {
10928: {0x001, LANG_ENGLISH, SUBLANG_ENGLISH_US}, // United States
10929: {0x002, LANG_FRENCH, SUBLANG_FRENCH_CANADIAN}, // Canadian-French
10930: {0x004, LANG_ENGLISH, SUBLANG_ENGLISH_CAN}, // Canada (English)
10931: {0x007, LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA}, // Russia
10932: {0x014, LANG_ARABIC, SUBLANG_ARABIC_EGYPT}, // Egypt
10933: {0x01B, LANG_ZULU, SUBLANG_ZULU_SOUTH_AFRICA}, // South Africa
10934: // {0x01B, LANG_XHOSA, SUBLANG_XHOSA_SOUTH_AFRICA}, // South Africa
10935: // {0x01B, LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA}, // South Africa
10936: // {0x01B, LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA}, // South Africa
10937: // {0x01B, LANG_SOTHO, SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA}, // South Africa
10938: // {0x01B, LANG_TSWANA, SUBLANG_TSWANA_SOUTH_AFRICA}, // South Africa
10939: {0x01E, LANG_GREEK, SUBLANG_GREEK_GREECE}, // Greece
10940: {0x01F, LANG_DUTCH, SUBLANG_DUTCH}, // Netherlands
10941: // {0x01F, LANG_FRISIAN, SUBLANG_FRISIAN_NETHERLANDS}, // Netherlands
10942: {0x020, LANG_DUTCH, SUBLANG_DUTCH_BELGIAN}, // Belgium
10943: // {0x020, LANG_FRENCH, SUBLANG_FRENCH_BELGIAN}, // Belgium
10944: {0x021, LANG_FRENCH, SUBLANG_FRENCH}, // France
10945: {0x022, LANG_SPANISH, SUBLANG_SPANISH}, // Spain
10946: {0x023, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria???
10947: {0x024, LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY}, // Hungary (not supported by DR DOS 5.0)
10948: {0x027, LANG_ITALIAN, SUBLANG_ITALIAN}, // Italy / San Marino / Vatican City
10949: {0x028, LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA}, // Romania
10950: {0x029, LANG_GERMAN, SUBLANG_GERMAN_SWISS}, // Switzerland / Liechtenstein
10951: // {0x029, LANG_FRENCH, SUBLANG_FRENCH_SWISS}, // Switzerland / Liechtenstein
10952: // {0x029, LANG_ITALIAN, SUBLANG_ITALIAN_SWISS}, // Switzerland / Liechtenstein
10953: {0x02A, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0)
10954: {0x02B, LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN}, // Austria (DR DOS 5.0)
10955: {0x02C, LANG_ENGLISH, SUBLANG_ENGLISH_UK}, // United Kingdom
10956: {0x02D, LANG_DANISH, SUBLANG_DANISH_DENMARK}, // Denmark
10957: {0x02E, LANG_SWEDISH, SUBLANG_SWEDISH}, // Sweden
10958: // {0x02E, LANG_SAMI, SUBLANG_SAMI_NORTHERN_SWEDEN}, // Sweden
10959: // {0x02E, LANG_SAMI, SUBLANG_SAMI_LULE_SWEDEN}, // Sweden
10960: // {0x02E, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_SWEDEN}, // Sweden
10961: {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL}, // Norway
10962: // {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK}, // Norway
10963: // {0x02F, LANG_SAMI, SUBLANG_SAMI_NORTHERN_NORWAY}, // Norway
10964: // {0x02F, LANG_SAMI, SUBLANG_SAMI_LULE_NORWAY}, // Norway
10965: // {0x02F, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_NORWAY}, // Norway
10966: {0x030, LANG_POLISH, SUBLANG_POLISH_POLAND}, // Poland (not supported by DR DOS 5.0)
10967: {0x031, LANG_GERMAN, SUBLANG_GERMAN}, // Germany
10968: {0x033, LANG_SPANISH, SUBLANG_SPANISH_PERU}, // Peru
10969: // {0x033, LANG_QUECHUA, SUBLANG_QUECHUA_PERU}, // Peru
10970: {0x034, LANG_SPANISH, SUBLANG_SPANISH_MEXICAN}, // Mexico
10971: {0x035, LANG_SPANISH, SUBLANG_NEUTRAL}, // Cuba
10972: {0x036, LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA}, // Argentina
10973: {0x037, LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN}, // Brazil (not supported by DR DOS 5.0)
10974: {0x038, LANG_SPANISH, SUBLANG_SPANISH_CHILE}, // Chile
10975: {0x039, LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA}, // Columbia
10976: {0x03A, LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA}, // Venezuela
10977: {0x03C, LANG_MALAY, SUBLANG_MALAY_MALAYSIA}, // Malaysia
10978: {0x03D, LANG_ENGLISH, SUBLANG_ENGLISH_AUS}, // International English / Australia
10979: {0x03E, LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA}, // Indonesia / East Timor
10980: {0x03F, LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES}, // Philippines
10981: {0x040, LANG_ENGLISH, SUBLANG_ENGLISH_NZ}, // New Zealand
10982: {0x041, LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE}, // Singapore
10983: // {0x041, LANG_ENGLISH, SUBLANG_ENGLISH_SINGAPORE}, // Singapore
10984: {0x042, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan???
10985: {0x051, LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN}, // Japan (DR DOS 5.0, MS-DOS 5.0+)
10986: {0x052, LANG_KOREAN, SUBLANG_KOREAN}, // South Korea (DR DOS 5.0)
10987: {0x054, LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM}, // Vietnam
10988: {0x056, LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED}, // China (MS-DOS 5.0+)
10989: {0x058, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (MS-DOS 5.0+)
10990: {0x05A, LANG_TURKISH, SUBLANG_TURKISH_TURKEY}, // Turkey (MS-DOS 5.0+)
10991: {0x05B, LANG_HINDI, SUBLANG_HINDI_INDIA}, // India
10992: {0x05C, LANG_URDU, SUBLANG_URDU_PAKISTAN}, // Pakistan
10993: {0x05D, LANG_PASHTO, SUBLANG_PASHTO_AFGHANISTAN}, // Afghanistan
10994: // {0x05D, LANG_DARI, SUBLANG_DARI_AFGHANISTAN}, // Afghanistan
10995: {0x05E, LANG_SINHALESE, SUBLANG_SINHALESE_SRI_LANKA}, // Sri Lanka
10996: // {0x05E, LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA}, // Sri Lanka
10997: {0x062, LANG_PERSIAN, SUBLANG_PERSIAN_IRAN}, // Iran
10998: {0x070, LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS}, // Belarus
10999: {0x0C8, LANG_THAI, SUBLANG_THAI_THAILAND}, // Thailand
11000: {0x0D4, LANG_ARABIC, SUBLANG_ARABIC_MOROCCO}, // Morocco
11001: {0x0D5, LANG_ARABIC, SUBLANG_ARABIC_ALGERIA}, // Algeria
11002: {0x0D8, LANG_ARABIC, SUBLANG_ARABIC_TUNISIA}, // Tunisia
11003: {0x0DA, LANG_ARABIC, SUBLANG_ARABIC_LIBYA}, // Libya
11004: {0x0DD, LANG_WOLOF, SUBLANG_WOLOF_SENEGAL}, // Senegal
11005: // {0x0DD, LANG_PULAR, SUBLANG_PULAR_SENEGAL}, // Senegal
11006: {0x0EA, LANG_HAUSA, SUBLANG_HAUSA_NIGERIA_LATIN}, // Nigeria
11007: // {0x0EA, LANG_YORUBA, SUBLANG_YORUBA_NIGERIA}, // Nigeria
11008: // {0x0EA, LANG_IGBO, SUBLANG_IGBO_NIGERIA}, // Nigeria
11009: {0x0FB, LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA}, // Ethiopia
11010: // {0x0FB, LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA}, // Ethiopia
11011: {0x0FE, LANG_SWAHILI, SUBLANG_SWAHILI}, // Kenya
11012: {0x107, LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE}, // Zimbabwe
11013: {0x10B, LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA}, // Botswana
11014: {0x12A, LANG_FAEROESE, SUBLANG_FAEROESE_FAROE_ISLANDS}, // Faroe Islands
11015: {0x12B, LANG_GREENLANDIC, SUBLANG_GREENLANDIC_GREENLAND}, // Greenland
11016: {0x15F, LANG_PORTUGUESE, SUBLANG_PORTUGUESE}, // Portugal
11017: {0x160, LANG_LUXEMBOURGISH, SUBLANG_LUXEMBOURGISH_LUXEMBOURG}, // Luxembourg
11018: // {0x160, LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG}, // Luxembourg
11019: // {0x160, LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG}, // Luxembourg
11020: {0x161, LANG_IRISH, SUBLANG_IRISH_IRELAND}, // Ireland
11021: // {0x161, LANG_ENGLISH, SUBLANG_ENGLISH_IRELAND}, // Ireland
11022: {0x162, LANG_ICELANDIC, SUBLANG_ICELANDIC_ICELAND}, // Iceland
11023: {0x163, LANG_ALBANIAN, SUBLANG_ALBANIAN_ALBANIA}, // Albania
11024: {0x164, LANG_MALTESE, SUBLANG_MALTESE_MALTA}, // Malta
11025: {0x166, LANG_FINNISH, SUBLANG_FINNISH_FINLAND}, // Finland
11026: // {0x166, LANG_SAMI, SUBLANG_SAMI_NORTHERN_FINLAND}, // Finland
11027: // {0x166, LANG_SAMI, SUBLANG_SAMI_SKOLT_FINLAND}, // Finland
11028: // {0x166, LANG_SAMI, SUBLANG_SAMI_INARI_FINLAND}, // Finland
11029: {0x167, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria
11030: {0x172, LANG_LITHUANIAN, SUBLANG_LITHUANIAN_LITHUANIA}, // Lithuania
11031: {0x173, LANG_LATVIAN, SUBLANG_LATVIAN_LATVIA}, // Latvia
11032: {0x174, LANG_ESTONIAN, SUBLANG_ESTONIAN_ESTONIA}, // Estonia
11033: {0x17D, LANG_SERBIAN, SUBLANG_SERBIAN_LATIN}, // Serbia / Montenegro
11034: {0x180, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia???
11035: {0x181, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia
11036: {0x182, LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA}, // Slovenia
11037: {0x183, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN}, // Bosnia-Herzegovina (Latin)
11038: {0x184, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC}, // Bosnia-Herzegovina (Cyrillic)
11039: {0x185, LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA}, // FYR Macedonia
11040: {0x1A5, LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC}, // Czech Republic
11041: {0x1A6, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Slovakia
11042: {0x1F5, LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE}, // Belize
11043: {0x1F6, LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA}, // Guatemala
11044: {0x1F7, LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR}, // El Salvador
11045: {0x1F8, LANG_SPANISH, SUBLANG_SPANISH_HONDURAS}, // Honduras
11046: {0x1F9, LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA}, // Nicraragua
11047: {0x1FA, LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA}, // Costa Rica
11048: {0x1FB, LANG_SPANISH, SUBLANG_SPANISH_PANAMA}, // Panama
11049: {0x24F, LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA}, // Bolivia
11050: // {0x24F, LANG_QUECHUA, SUBLANG_QUECHUA_BOLIVIA}, // Bolivia
11051: {0x251, LANG_SPANISH, SUBLANG_SPANISH_ECUADOR}, // Ecuador
11052: // {0x251, LANG_QUECHUA, SUBLANG_QUECHUA_ECUADOR}, // Ecuador
11053: {0x253, LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY}, // Paraguay
11054: {0x256, LANG_SPANISH, SUBLANG_SPANISH_URUGUAY}, // Uruguay
11055: {0x2A1, LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM}, // Brunei Darussalam
11056: {0x311, LANG_ARABIC, SUBLANG_NEUTRAL}, // Arabic (Middle East/Saudi Arabia/etc.)
11057: {0x324, LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE}, // Ukraine
11058: {0x352, LANG_KOREAN, SUBLANG_KOREAN}, // North Korea
11059: {0x354, LANG_CHINESE, SUBLANG_CHINESE_HONGKONG}, // Hong Kong
11060: {0x355, LANG_CHINESE, SUBLANG_CHINESE_MACAU}, // Macao
11061: {0x357, LANG_KHMER, SUBLANG_KHMER_CAMBODIA}, // Cambodia
11062: {0x370, LANG_BANGLA, SUBLANG_BANGLA_BANGLADESH}, // Bangladesh
11063: {0x376, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (DOS 6.22+)
11064: {0x3C0, LANG_DIVEHI, SUBLANG_DIVEHI_MALDIVES}, // Maldives
11065: {0x3C1, LANG_ARABIC, SUBLANG_ARABIC_LEBANON}, // Lebanon
11066: {0x3C2, LANG_ARABIC, SUBLANG_ARABIC_JORDAN}, // Jordan
11067: {0x3C3, LANG_ARABIC, SUBLANG_ARABIC_SYRIA}, // Syrian Arab Republic
11068: {0x3C4, LANG_ARABIC, SUBLANG_ARABIC_IRAQ}, // Ireq
11069: {0x3C5, LANG_ARABIC, SUBLANG_ARABIC_KUWAIT}, // Kuwait
11070: {0x3C6, LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA}, // Saudi Arabia
11071: {0x3C7, LANG_ARABIC, SUBLANG_ARABIC_YEMEN}, // Yemen
11072: {0x3C8, LANG_ARABIC, SUBLANG_ARABIC_OMAN}, // Oman
11073: {0x3CB, LANG_ARABIC, SUBLANG_ARABIC_UAE}, // United Arab Emirates
11074: {0x3CC, LANG_HEBREW, SUBLANG_HEBREW_ISRAEL}, // Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+)
11075: {0x3CD, LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN}, // Bahrain
11076: {0x3CE, LANG_ARABIC, SUBLANG_ARABIC_QATAR}, // Qatar
11077: {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA}, // Mongolia
11078: // {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_PRC}, // Mongolia
11079: {0x3D1, LANG_NEPALI, SUBLANG_NEPALI_NEPAL}, // Nepal
11080: {-1, 0, 0},
11081: };
11082:
11083: inline void msdos_int_21h_38h()
11084: {
11085: switch(REG8(AL)) {
11086: case 0x00:
11087: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
11088: break;
11089: default:
11090: for(int i = 0;; i++) {
11091: if(country_table[i].code == (REG8(AL) != 0xff ? REG8(AL) : REG16(BX))) {
11092: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
11093: break;
11094: } else if(country_table[i].code == -1) {
11095: // 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));
11096: // REG16(AX) = 2;
11097: // m_CF = 1;
11098: // get current coutry info
11099: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
11100: break;
11101: }
11102: }
11103: break;
11104: }
11105: }
11106:
11107: inline void msdos_int_21h_39h(int lfn)
11108: {
11109: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
11110: REG16(AX) = errno;
11111: m_CF = 1;
11112: }
11113: }
11114:
11115: inline void msdos_int_21h_3ah(int lfn)
11116: {
11117: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
11118: REG16(AX) = errno;
11119: m_CF = 1;
11120: }
11121: }
11122:
11123: inline void msdos_int_21h_3bh(int lfn)
11124: {
11125: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
11126:
11127: if(_chdir(path)) {
11128: REG16(AX) = 3; // must be 3 (path not found)
11129: m_CF = 1;
11130: } else {
11131: int drv = _getdrive() - 1;
11132: if(path[1] == ':') {
11133: if(path[0] >= 'A' && path[0] <= 'Z') {
11134: drv = path[0] - 'A';
11135: } else if(path[0] >= 'a' && path[0] <= 'z') {
11136: drv = path[0] - 'a';
11137: }
11138: }
11139: msdos_cds_update(drv, path);
11140: }
11141: }
11142:
11143: inline void msdos_int_21h_3ch()
11144: {
11145: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
11146: int attr = GetFileAttributesA(path);
11147: int fd = -1;
11148: int sio_port = 0;
11149: int lpt_port = 0;
11150:
11151: if(msdos_is_device_path(path)) {
11152: fd = msdos_open_device(path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
11153: } else {
11154: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11155: }
11156: if(fd != -1) {
11157: if(attr == -1) {
11158: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
11159: }
11160: SetFileAttributesA(path, attr);
11161: REG16(AX) = fd;
11162: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port);
11163: msdos_psp_set_file_table(fd, fd, current_psp);
11164: } else {
11165: REG16(AX) = errno;
11166: m_CF = 1;
11167: }
11168: }
11169:
11170: inline void msdos_int_21h_3dh()
11171: {
11172: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
11173: int mode = REG8(AL) & 0x03;
11174: int fd = -1;
11175: int sio_port = 0;
11176: int lpt_port = 0;
11177:
11178: if(mode < 0x03) {
11179: if(msdos_is_device_path(path)) {
11180: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
11181: } else {
11182: fd = msdos_open(path, file_mode[mode].mode);
11183: }
11184: if(fd != -1) {
11185: REG16(AX) = fd;
11186: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port);
11187: msdos_psp_set_file_table(fd, fd, current_psp);
11188: } else {
11189: REG16(AX) = errno;
11190: m_CF = 1;
11191: }
11192: } else {
11193: REG16(AX) = 0x0c;
11194: m_CF = 1;
11195: }
11196: }
11197:
11198: inline void msdos_int_21h_3eh()
11199: {
11200: process_t *process = msdos_process_info_get(current_psp);
11201: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11202:
11203: if(fd < process->max_files && file_handler[fd].valid) {
11204: _close(fd);
11205: msdos_file_handler_close(fd);
11206: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
11207: } else {
11208: REG16(AX) = 0x06;
11209: m_CF = 1;
11210: }
11211: }
11212:
11213: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID)
11214: {
11215: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
11216: int max = REG16(CX);
11217: int p = 0;
11218:
11219: while(max > p) {
11220: int chr = msdos_getch();
11221:
11222: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
11223: p = 0;
11224: buf[p++] = 0x0d;
11225: if(max > p) {
11226: buf[p++] = 0x0a;
11227: }
11228: msdos_putch(0x03);
11229: msdos_putch(0x0d);
11230: msdos_putch(0x0a);
11231: break;
11232: } else if(ctrl_break_pressed) {
11233: // skip this byte
11234: } else if(chr == 0x00) {
11235: // skip 2nd byte
11236: msdos_getch();
11237: } else if(chr == 0x0d) {
11238: // carriage return
11239: buf[p++] = 0x0d;
11240: if(max > p) {
11241: buf[p++] = 0x0a;
11242: }
11243: msdos_putch('\n');
11244: break;
11245: } else if(chr == 0x08) {
11246: // back space
11247: if(p > 0) {
11248: p--;
11249: if(msdos_ctrl_code_check(buf[p])) {
11250: msdos_putch(0x08);
11251: msdos_putch(0x08);
11252: msdos_putch(0x20);
11253: msdos_putch(0x20);
11254: msdos_putch(0x08);
11255: msdos_putch(0x08);
11256: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
11257: p--;
11258: msdos_putch(0x08);
11259: msdos_putch(0x08);
11260: msdos_putch(0x20);
11261: msdos_putch(0x20);
11262: msdos_putch(0x08);
11263: msdos_putch(0x08);
11264: } else {
11265: msdos_putch(0x08);
11266: msdos_putch(0x20);
11267: msdos_putch(0x08);
11268: }
11269: }
11270: } else if(chr == 0x1b) {
11271: // escape
11272: while(p > 0) {
11273: p--;
11274: if(msdos_ctrl_code_check(buf[p])) {
11275: msdos_putch(0x08);
11276: msdos_putch(0x08);
11277: msdos_putch(0x20);
11278: msdos_putch(0x20);
11279: msdos_putch(0x08);
11280: msdos_putch(0x08);
11281: } else {
11282: msdos_putch(0x08);
11283: msdos_putch(0x20);
11284: msdos_putch(0x08);
11285: }
11286: }
11287: } else {
11288: buf[p++] = chr;
11289: msdos_putch(chr);
11290: }
11291: }
11292: REG16(AX) = p;
11293:
11294: #ifdef USE_SERVICE_THREAD
11295: service_exit = true;
11296: #endif
11297: return(0);
11298: }
11299:
11300: inline void msdos_int_21h_3fh()
11301: {
11302: process_t *process = msdos_process_info_get(current_psp);
11303: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11304:
11305: if(fd < process->max_files && file_handler[fd].valid) {
11306: if(file_mode[file_handler[fd].mode].in) {
11307: if(file_handler[fd].atty) {
11308: // BX is stdin or is redirected to stdin
11309: if(REG16(CX) != 0) {
11310: #ifdef USE_SERVICE_THREAD
11311: if(!in_service && !in_service_29h &&
11312: *(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) &&
11313: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
11314: // msdos_putch() will be used in this service
11315: // if int 29h is hooked, run this service in main thread to call int 29h
11316: start_service_loop(msdos_int_21h_3fh_thread);
11317: } else {
11318: #endif
11319: msdos_int_21h_3fh_thread(NULL);
11320: REQUEST_HARDWRE_UPDATE();
11321: #ifdef USE_SERVICE_THREAD
11322: }
11323: #endif
11324: } else {
11325: REG16(AX) = 0;
11326: }
11327: } else {
11328: REG16(AX) = msdos_read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
11329: }
11330: } else {
11331: REG16(AX) = 0x05;
11332: m_CF = 1;
11333: }
11334: } else {
11335: REG16(AX) = 0x06;
11336: m_CF = 1;
11337: }
11338: }
11339:
11340: inline void msdos_int_21h_40h()
11341: {
11342: process_t *process = msdos_process_info_get(current_psp);
11343: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11344:
11345: if(fd < process->max_files && file_handler[fd].valid) {
11346: if(file_mode[file_handler[fd].mode].out) {
11347: if(REG16(CX)) {
11348: if(file_handler[fd].atty) {
11349: // BX is stdout/stderr or is redirected to stdout
11350: for(int i = 0; i < REG16(CX); i++) {
11351: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
11352: }
11353: REG16(AX) = REG16(CX);
11354: } else {
11355: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
11356: }
11357: } else {
11358: UINT32 pos = _tell(fd);
11359: _lseek(fd, 0, SEEK_END);
11360: UINT32 size = _tell(fd);
11361: if(pos < size) {
11362: _lseek(fd, pos, SEEK_SET);
11363: SetEndOfFile((HANDLE)_get_osfhandle(fd));
11364: } else {
11365: for(UINT32 i = size; i < pos; i++) {
11366: UINT8 tmp = 0;
11367: msdos_write(fd, &tmp, 1);
11368: }
11369: _lseek(fd, pos, SEEK_SET);
11370: }
11371: REG16(AX) = 0;
11372: }
11373: } else {
11374: REG16(AX) = 0x05;
11375: m_CF = 1;
11376: }
11377: } else {
11378: REG16(AX) = 0x06;
11379: m_CF = 1;
11380: }
11381: }
11382:
11383: inline void msdos_int_21h_41h(int lfn)
11384: {
11385: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
11386: REG16(AX) = errno;
11387: m_CF = 1;
11388: }
11389: }
11390:
11391: inline void msdos_int_21h_42h()
11392: {
11393: process_t *process = msdos_process_info_get(current_psp);
11394: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11395:
11396: if(fd < process->max_files && file_handler[fd].valid) {
11397: if(REG8(AL) < 0x03) {
11398: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
11399: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
11400: UINT32 pos = _tell(fd);
11401: REG16(AX) = pos & 0xffff;
11402: REG16(DX) = (pos >> 16);
11403: } else {
11404: REG16(AX) = 0x01;
11405: m_CF = 1;
11406: }
11407: } else {
11408: REG16(AX) = 0x06;
11409: m_CF = 1;
11410: }
11411: }
11412:
11413: inline void msdos_int_21h_43h(int lfn)
11414: {
11415: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
11416: int attr;
11417:
11418: if(!lfn && REG8(AL) > 2) {
11419: REG16(AX) = 0x01;
11420: m_CF = 1;
11421: return;
11422: }
11423: switch(REG8(lfn ? BL : AL)) {
11424: case 0x00:
11425: if((attr = GetFileAttributesA(path)) != -1) {
11426: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
11427: } else {
11428: REG16(AX) = (UINT16)GetLastError();
11429: m_CF = 1;
11430: }
11431: break;
11432: case 0x01:
11433: if(!SetFileAttributesA(path, msdos_file_attribute_create(REG16(CX)))) {
11434: REG16(AX) = (UINT16)GetLastError();
11435: m_CF = 1;
11436: }
11437: break;
11438: case 0x02:
11439: {
11440: DWORD compressed_size = GetCompressedFileSizeA(path, NULL), file_size = 0;
11441: if(compressed_size != INVALID_FILE_SIZE) {
11442: if(compressed_size != 0) {
11443: HANDLE hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
11444: if(hFile != INVALID_HANDLE_VALUE) {
11445: file_size = GetFileSize(hFile, NULL);
11446: CloseHandle(hFile);
11447: }
11448: if(compressed_size == file_size) {
11449: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
11450: // this isn't correct if the file is in the NTFS MFT
11451: if(GetDiskFreeSpaceA(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
11452: compressed_size = ((compressed_size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
11453: }
11454: }
11455: }
11456: REG16(AX) = LOWORD(compressed_size);
11457: REG16(DX) = HIWORD(compressed_size);
11458: } else {
11459: REG16(AX) = (UINT16)GetLastError();
11460: m_CF = 1;
11461: }
11462: }
11463: break;
11464: case 0x03:
11465: case 0x05:
11466: case 0x07:
11467: if(lfn) {
11468: HANDLE hFile = CreateFileA(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
11469: if(hFile != INVALID_HANDLE_VALUE) {
11470: FILETIME local, time;
11471: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
11472: if(REG8(BL) == 7) {
11473: ULARGE_INTEGER hund;
11474: hund.LowPart = local.dwLowDateTime;
11475: hund.HighPart = local.dwHighDateTime;
11476: hund.QuadPart += REG16(SI) * 100000;
11477: local.dwLowDateTime = hund.LowPart;
11478: local.dwHighDateTime = hund.HighPart;
11479: }
11480: LocalFileTimeToFileTime(&local, &time);
11481: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
11482: REG8(BL) == 0x05 ? &time : NULL,
11483: REG8(BL) == 0x03 ? &time : NULL)) {
11484: REG16(AX) = (UINT16)GetLastError();
11485: m_CF = 1;
11486: }
11487: CloseHandle(hFile);
11488: } else {
11489: REG16(AX) = (UINT16)GetLastError();
11490: m_CF = 1;
11491: }
11492: } else {
11493: // 214303 DR DOS 3.41+ internal - Set Access Rights And Password
11494: // 214305 DR DOS 5.0-6.0 internal - Set Extended File Attributes
11495: // 214307 DR DOS 6.0 - Set File Owner
11496: // 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));
11497: REG16(AX) = 0x01;
11498: m_CF = 1;
11499: }
11500: break;
11501: case 0x04:
11502: case 0x06:
11503: case 0x08:
11504: if(lfn) {
11505: WIN32_FILE_ATTRIBUTE_DATA fad;
11506: if(GetFileAttributesExA(path, GetFileExInfoStandard, (LPVOID)&fad)) {
11507: FILETIME *time, local;
11508: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
11509: 0x06 ? &fad.ftLastAccessTime :
11510: &fad.ftCreationTime;
11511: FileTimeToLocalFileTime(time, &local);
11512: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
11513: if(REG8(BL) == 0x08) {
11514: ULARGE_INTEGER hund;
11515: hund.LowPart = local.dwLowDateTime;
11516: hund.HighPart = local.dwHighDateTime;
11517: hund.QuadPart /= 100000;
11518: REG16(SI) = (UINT16)(hund.QuadPart % 200);
11519: }
11520: } else {
11521: REG16(AX) = (UINT16)GetLastError();
11522: m_CF = 1;
11523: }
11524: } else {
11525: // 214304 DR DOS 5.0-6.0 internal - Get Encrypted Password
11526: // 214306 DR DOS 6.0 - Get File Owner
11527: // 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));
11528: REG16(AX) = 0x01;
11529: m_CF = 1;
11530: }
11531: break;
11532: case 0xff:
11533: if(!lfn && REG16(BP) == 0x5053) {
11534: if(REG8(CL) == 0x39) {
11535: msdos_int_21h_39h(1);
11536: break;
11537: } else if(REG8(CL) == 0x56) {
11538: msdos_int_21h_56h(1);
11539: break;
11540: }
11541: }
11542: default:
11543: 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));
11544: REG16(AX) = lfn ? 0x7100 : 0x01;
11545: m_CF = 1;
11546: break;
11547: }
11548: }
11549:
11550: inline void msdos_int_21h_44h()
11551: {
11552: static UINT16 iteration_count = 0;
11553:
11554: process_t *process;
11555: int fd, drv;
11556:
11557: switch(REG8(AL)) {
11558: case 0x00:
11559: case 0x01:
11560: case 0x02:
11561: case 0x03:
11562: case 0x04:
11563: case 0x05:
11564: case 0x06:
11565: case 0x07:
11566: process = msdos_process_info_get(current_psp);
11567: fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11568: if(fd >= process->max_files || !file_handler[fd].valid) {
11569: REG16(AX) = 0x06;
11570: m_CF = 1;
11571: return;
11572: }
11573: break;
11574: case 0x08:
11575: case 0x09:
11576: drv = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
11577: if(!msdos_is_valid_drive(drv)) {
11578: // invalid drive
11579: REG16(AX) = 0x0f;
11580: m_CF = 1;
11581: return;
11582: }
11583: break;
11584: }
11585: switch(REG8(AL)) {
11586: case 0x00: // Get Device Information
11587: REG16(DX) = file_handler[fd].info;
11588: break;
11589: case 0x01: // Set Device Information
11590: if(REG8(DH) != 0) {
11591: // REG16(AX) = 0x0d; // data invalid
11592: // m_CF = 1;
11593: file_handler[fd].info = REG16(DX);
11594: } else {
11595: file_handler[fd].info &= 0xff00;
11596: file_handler[fd].info |= REG8(DL);
11597: }
11598: break;
11599: case 0x02: // Read From Character Device Control Channel
11600: if(strstr(file_handler[fd].path, "EMMXXXX0") != NULL && support_ems) {
11601: // from DOSBox
11602: switch(*(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX))) {
11603: case 0x00:
11604: if(REG16(CX) >= 6) {
11605: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0023;
11606: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0000;
11607: REG16(AX) = 6; // number of bytes actually read
11608: } else {
11609: REG16(AX) = 0x0d; // data invalid
11610: m_CF = 1;
11611: }
11612: break;
11613: case 0x01:
11614: if(REG16(CX) >= 6) {
11615: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x000) = 0x0004; // flags
11616: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x002) = 0x019d; // size of this structure
11617: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x004) = 0x0001; // version 1.0
11618: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x006) = 0x00000000; // reserved
11619: for(int addr = 0, ofs = 0x00a; addr < 0x100000; addr += 0x4000, ofs += 6) {
11620: if(addr >= EMS_TOP && addr < EMS_TOP + EMS_SIZE) {
11621: int page = (addr - EMS_TOP) / 0x4000;
11622: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x03; // frame type: EMS frame in 64k page
11623: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE
11624: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0x7fff; // no logical page number
11625: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = page; // physical EMS page number
11626: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0x00; // flags: EMS frame
11627: } else {
11628: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x00; // frame type: NONE
11629: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE
11630: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0xffff; // non-EMS frame
11631: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = 0xff; // EMS page number (NONE)
11632: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0xaa; // flags: direct mapping
11633: }
11634: }
11635: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18a) = 0x74; // ??
11636: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18b) = 0x00; // no UMB descriptors following
11637: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18c) = 0x01; // 1 EMS handle info record
11638: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x17d) = 0x0000; // system handle
11639: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x18f) = 0x00000000; // handle name
11640: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x193) = 0x00000000; // handle name
11641: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x197) = 0x0001; // system handle
11642: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x199) = 0x00110000; // physical address
11643:
11644: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0018;
11645: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = XMS_TOP >> 4;
11646: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4) = 0x0001; // version 1.0
11647: REG16(AX) = 6; // number of bytes actually read
11648: } else {
11649: REG16(AX) = 0x0d; // data invalid
11650: m_CF = 1;
11651: }
11652: break;
11653: case 0x02:
11654: if(REG16(CX) >= 2) {
11655: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x40; // EMS 4.0
11656: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 1) = 0x00;
11657: REG16(AX) = 2; // number of bytes actually read
11658: } else {
11659: REG16(AX) = 0x0d; // data invalid
11660: m_CF = 1;
11661: }
11662: break;
11663: case 0x03:
11664: if(REG16(CX) >= 4) {
11665: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = MAX_EMS_PAGES * 16; // max size (kb)
11666: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0080; // min size (kb)
11667: REG16(AX) = 4; // number of bytes actually read
11668: } else {
11669: REG16(AX) = 0x0d; // data invalid
11670: m_CF = 1;
11671: }
11672: break;
11673: default:
11674: REG16(AX) = 0x01; // function number invalid
11675: m_CF = 1;
11676: }
11677: } else if(strstr(file_handler[fd].path, "CONFIG$") != NULL) {
11678: if(REG16(CX) >= 5) {
11679: memset(mem + SREG_BASE(DS) + REG16(DX), 0, 5);
11680: REG16(AX) = 5; // number of bytes actually read
11681: } else {
11682: REG16(AX) = 0x0d; // data invalid
11683: m_CF = 1;
11684: }
11685: } else {
11686: // memset(mem + SREG_BASE(DS) + REG16(DX), 0, REG16(CX));
11687: // REG16(AX) = REG16(CX);
11688: REG16(AX) = 0x05; // access denied
11689: m_CF = 1;
11690: }
11691: break;
11692: case 0x03: // Write To Character Device Control Channel
11693: // REG16(AX) = 0x05;
11694: // m_CF = 1;
11695: REG16(AX) = 0x00; // success
11696: break;
11697: case 0x04: // Read From Block Device Control Channel
11698: case 0x05: // Write To Block Device Control Channel
11699: REG16(AX) = 0x05;
11700: m_CF = 1;
11701: break;
11702: case 0x06: // Get Input Status
11703: if(file_mode[file_handler[fd].mode].in) {
11704: if(file_handler[fd].atty) {
11705: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
11706: } else {
11707: REG8(AL) = eof(fd) ? 0x00 : 0xff;
11708: }
11709: } else {
11710: REG8(AL) = 0x00;
11711: }
11712: break;
11713: case 0x07: // Get Output Status
11714: if(file_mode[file_handler[fd].mode].out) {
11715: REG8(AL) = 0xff;
11716: } else {
11717: REG8(AL) = 0x00;
11718: }
11719: break;
11720: case 0x08: // Check If Block Device Removable
11721: if(msdos_is_removable_drive(drv) || msdos_is_cdrom_drive(drv)) {
11722: // removable drive
11723: REG16(AX) = 0x00;
11724: } else {
11725: // fixed drive
11726: REG16(AX) = 0x01;
11727: }
11728: break;
11729: case 0x09: // Check If Block Device Remote
11730: if(msdos_is_remote_drive(drv)) {
11731: // remote drive
11732: REG16(DX) = 0x1000;
11733: } else if(msdos_is_subst_drive(drv)) {
11734: // subst drive
11735: REG16(DX) = 0x8000;
11736: } else {
11737: // local drive
11738: REG16(DX) = 0x0000;
11739: }
11740: break;
11741: case 0x0a: // Check If Handle Is Remote
11742: if(!(file_handler[fd].info & 0x8000) && msdos_is_remote_drive(msdos_drive_number(file_handler[fd].path))) {
11743: REG16(DX) = 0x8000;
11744: } else {
11745: REG16(DX) = 0x0000;
11746: }
11747: break;
11748: case 0x0b: // Set Sharing Retry Count
11749: break;
11750: case 0x0c: // Generic Character Device Request
11751: if(REG8(CL) == 0x45) {
11752: // set iteration (retry) count
11753: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
11754: } else if(REG8(CL) == 0x4a) {
11755: // select code page
11756: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
11757: msdos_nls_tables_update();
11758: } else if(REG8(CL) == 0x4c) {
11759: // start code-page preparation
11760: int ids[3] = {437, 0, 0}; // 437: US English
11761: int count = 1, offset = 0;
11762: if(active_code_page != 437) {
11763: ids[count++] = active_code_page;
11764: }
11765: if(system_code_page != 437 && system_code_page != active_code_page) {
11766: ids[count++] = system_code_page;
11767: }
11768: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 0;
11769: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 + 2 * count;
11770: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
11771: for(int i = 0; i < count; i++) {
11772: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
11773: }
11774: } else if(REG8(CL) == 0x4d) {
11775: // end code-page preparation
11776: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2;
11777: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
11778: } else if(REG8(CL) == 0x5f) {
11779: // set display information
11780: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) >= 14) {
11781: int cur_width = *(UINT16 *)(mem + 0x44a) + 0;
11782: int cur_height = *(UINT8 *)(mem + 0x484) + 1;
11783: int new_width = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // character columns
11784: int new_height = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10); // character rows
11785:
11786: if(cur_width != new_width || cur_height != new_height) {
11787: pcbios_set_console_size(new_width, new_height, true);
11788: }
11789: }
11790: } else if(REG8(CL) == 0x65) {
11791: // get iteration (retry) count
11792: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
11793: } else if(REG8(CL) == 0x6a) {
11794: // query selected code page
11795: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
11796: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
11797:
11798: CPINFO info;
11799: GetCPInfo(active_code_page, &info);
11800:
11801: if(info.MaxCharSize != 1) {
11802: for(int i = 0;; i++) {
11803: UINT8 lo = info.LeadByte[2 * i + 0];
11804: UINT8 hi = info.LeadByte[2 * i + 1];
11805:
11806: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
11807: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
11808: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
11809:
11810: if(lo == 0 && hi == 0) {
11811: break;
11812: }
11813: }
11814: }
11815: } else if(REG8(CL) == 0x6b) {
11816: // query prepare list
11817: int ids[3] = {437, 0, 0}; // 437: US English
11818: int count = 1, offset = 0;
11819: if(active_code_page != 437) {
11820: ids[count++] = active_code_page;
11821: }
11822: if(system_code_page != 437 && system_code_page != active_code_page) {
11823: ids[count++] = system_code_page;
11824: }
11825: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 * (2 + 2 * count);
11826: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
11827: for(int i = 0; i < count; i++) {
11828: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
11829: }
11830: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
11831: for(int i = 0; i < count; i++) {
11832: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
11833: }
11834: } else if(REG8(CL) == 0x7f) {
11835: // get display information
11836: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0; // level (0 for DOS 4.x-6.0)
11837: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0; // reserved (0)
11838: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14; // length of following data (14)
11839: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1; // bit 0 set for blink, clear for intensity
11840: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1; // mode type (1=text, 2=graphics)
11841: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0; // reserved (0)
11842: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4; // 4 bits per pixel
11843: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a) + 0); // pixel columns
11844: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1); // pixel rows
11845: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a) + 0; // character columns
11846: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1; // character rows
11847: } else {
11848: 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));
11849: REG16(AX) = 0x01; // invalid function
11850: m_CF = 1;
11851: }
11852: break;
11853: case 0x0d: // Generic Block Device Request
11854: if(REG8(CL) == 0x40) {
11855: // set device parameters
11856: // } else if(REG8(CL) == 0x41) {
11857: // // write logical device track
11858: // } else if(REG8(CL) == 0x42) {
11859: // // format and verify logical device track
11860: } else if(REG8(CL) == 0x46) {
11861: // set volume serial number
11862: } else if(REG8(CL) == 0x47) {
11863: // set access flag
11864: // } else if(REG8(CL) == 0x48) {
11865: // // set media lock state
11866: // } else if(REG8(CL) == 0x49) {
11867: // // eject media in drive
11868: } else if(REG8(CL) == 0x4a) {
11869: // lock logical volume
11870: } else if(REG8(CL) == 0x4b) {
11871: // lock physical volume
11872: } else if(REG8(CL) == 0x60) {
11873: // get device parameters
11874: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
11875:
11876: if(pcbios_update_drive_param(drive_num, 1)) {
11877: drive_param_t *drive_param = &drive_params[drive_num];
11878: DISK_GEOMETRY *geo = &drive_param->geometry;
11879:
11880: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
11881: switch(geo->MediaType) {
11882: case F5_360_512:
11883: case F5_320_512:
11884: case F5_320_1024:
11885: case F5_180_512:
11886: case F5_160_512:
11887: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
11888: break;
11889: case F5_1Pt2_512:
11890: case F3_1Pt2_512:
11891: case F3_1Pt23_1024:
11892: case F5_1Pt23_1024:
11893: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
11894: break;
11895: case F3_720_512:
11896: case F3_640_512:
11897: case F5_640_512:
11898: case F5_720_512:
11899: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
11900: break;
11901: case F8_256_128:
11902: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
11903: break;
11904: case FixedMedia:
11905: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
11906: break;
11907: case F3_1Pt44_512:
11908: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
11909: break;
11910: case F3_2Pt88_512:
11911: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
11912: break;
11913: default:
11914: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
11915: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
11916: break;
11917: }
11918: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo->MediaType == FixedMedia) ? 0x01 : 0x00;
11919: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo->Cylinders.QuadPart > 0xffff) ? 0xffff : geo->Cylinders.QuadPart;
11920: switch(geo->MediaType) {
11921: case F5_360_512:
11922: case F5_320_512:
11923: case F5_320_1024:
11924: case F5_180_512:
11925: case F5_160_512:
11926: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
11927: break;
11928: default:
11929: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
11930: break;
11931: }
11932: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo->BytesPerSector;
11933: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo->SectorsPerTrack * geo->TracksPerCylinder;
11934: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
11935: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
11936: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
11937: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
11938: switch(geo->MediaType) {
11939: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
11940: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
11941: break;
11942: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
11943: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
11944: break;
11945: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
11946: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
11947: break;
11948: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
11949: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
11950: break;
11951: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
11952: case F3_1Pt2_512:
11953: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
11954: case F5_720_512:
11955: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
11956: break;
11957: case FixedMedia: // hard disk
11958: case RemovableMedia:
11959: case Unknown:
11960: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
11961: break;
11962: default:
11963: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
11964: break;
11965: }
11966: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo->SectorsPerTrack;
11967: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
11968: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
11969: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo->TracksPerCylinder * geo->Cylinders.QuadPart;
11970: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo->Cylinders.QuadPart;
11971: // 21h BYTE device type
11972: // 22h WORD device attributes (removable or not, etc)
11973: } else {
11974: REG16(AX) = 0x0f; // invalid drive
11975: m_CF = 1;
11976: }
11977: // } else if(REG8(CL) == 0x61) {
11978: // // read logical device track
11979: // } else if(REG8(CL) == 0x62) {
11980: // // verify logical device track
11981: } else if(REG8(CL) == 0x66) {
11982: // get volume serial number
11983: char path[] = "A:\\";
11984: char volume_label[MAX_PATH];
11985: DWORD serial_number = 0;
11986: char file_system[MAX_PATH];
11987:
11988: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
11989:
11990: if(GetVolumeInformationA(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
11991: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
11992: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
11993: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
11994: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
11995: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
11996: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
11997: } else {
11998: REG16(AX) = 0x0f; // invalid drive
11999: m_CF = 1;
12000: }
12001: } else if(REG8(CL) == 0x67) {
12002: // get access flag
12003: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
12004: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
12005: } else if(REG8(CL) == 0x68) {
12006: // sense media type
12007: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
12008:
12009: if(pcbios_update_drive_param(drive_num, 1)) {
12010: drive_param_t *drive_param = &drive_params[drive_num];
12011: DISK_GEOMETRY *geo = &drive_param->geometry;
12012:
12013: switch(geo->MediaType) {
12014: case F3_720_512:
12015: case F5_720_512:
12016: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
12017: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
12018: break;
12019: case F3_1Pt44_512:
12020: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
12021: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
12022: break;
12023: case F3_2Pt88_512:
12024: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
12025: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
12026: break;
12027: default:
12028: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
12029: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
12030: break;
12031: }
12032: } else {
12033: REG16(AX) = 0x0f; // invalid drive
12034: m_CF = 1;
12035: }
12036: } else if(REG8(CL) == 0x6a) {
12037: // unlock logical volume
12038: } else if(REG8(CL) == 0x6b) {
12039: // unlock physical volume
12040: // } else if(REG8(CL) == 0x6c) {
12041: // // get lock flag
12042: // } else if(REG8(CL) == 0x6d) {
12043: // // enumerate open files
12044: // } else if(REG8(CL) == 0x6e) {
12045: // // find swap file
12046: // } else if(REG8(CL) == 0x6f) {
12047: // // get drive map information
12048: // } else if(REG8(CL) == 0x70) {
12049: // // get current lock state
12050: // } else if(REG8(CL) == 0x71) {
12051: // // get first cluster
12052: } else {
12053: 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));
12054: REG16(AX) = 0x01; // invalid function
12055: m_CF = 1;
12056: }
12057: break;
12058: case 0x0e: // Get Lgical Drive Map
12059: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12060: REG16(AX) = 0x0f; // invalid drive
12061: m_CF = 1;
12062: } else {
12063: REG8(AL) = 0;
12064: }
12065: break;
12066: case 0x0f: // Set Logical Drive Map
12067: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12068: REG16(AX) = 0x0f; // invalid drive
12069: m_CF = 1;
12070: }
12071: break;
12072: case 0x10: // Query Generic IOCTRL Capability (Handle)
12073: switch(REG8(CL)) {
12074: case 0x45:
12075: case 0x4a:
12076: case 0x4c:
12077: case 0x4d:
12078: case 0x65:
12079: case 0x6a:
12080: case 0x6b:
12081: case 0x7f:
12082: REG16(AX) = 0x0000; // supported
12083: break;
12084: default:
12085: REG8(AL) = 0x01; // ioctl capability not available
12086: m_CF = 1;
12087: break;
12088: }
12089: break;
12090: case 0x11: // Query Generic IOCTRL Capability (Drive)
12091: switch(REG8(CL)) {
12092: case 0x40:
12093: case 0x46:
12094: case 0x4a:
12095: case 0x4b:
12096: case 0x60:
12097: case 0x66:
12098: case 0x67:
12099: case 0x68:
12100: case 0x6a:
12101: case 0x6b:
12102: if(REG8(CH) == 0x00 || REG8(CH) == 0x01 || REG8(CH) == 0x03 || REG8(CH) == 0x05) {
12103: // CH = 00h Unknown
12104: // CH = 01h COMn:
12105: // CH = 03h CON
12106: // CH = 05h LPTn:
12107: REG16(AX) = 0x0000; // supported
12108: break;
12109: }
12110: default:
12111: REG8(AL) = 0x01; // ioctl capability not available
12112: m_CF = 1;
12113: break;
12114: }
12115: break;
12116: case 0x12: // DR DOS 5.0-6.0 - Determine DOS Type
12117: case 0x14: // DR DOS 5.0-6.0 - Set Global Password
12118: case 0x16: // DR DOS 5.0-6.0 - History Buffer, Share, And Hiload Control
12119: case 0x51: // Concurrent DOS v3.2+ - Installation Check
12120: case 0x52: // DR DOS 3.41+ - Determine DOS tTpe/Get DR DOS Version
12121: case 0x54: // DR DOS 3.41+ - Set Global Password
12122: case 0x56: // DR DOS 5.0+ - History Buffer Control
12123: case 0x57: // DR DOS 5.0-6.0 - Share/Hiload Control
12124: case 0x58: // DR DOS 5.0+ internal - Get Pointer To Internal Variable Table
12125: case 0x59: // DR Multiuser DOS 5.0 - API
12126: REG16(AX) = 0x01; // this is not DR-DOS
12127: m_CF = 1;
12128: break;
12129: default:
12130: 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));
12131: REG16(AX) = 0x01;
12132: m_CF = 1;
12133: break;
12134: }
12135: }
12136:
12137: inline void msdos_int_21h_45h()
12138: {
12139: process_t *process = msdos_process_info_get(current_psp);
12140: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12141:
12142: if(fd < process->max_files && file_handler[fd].valid) {
12143: int dup_fd = _dup(fd);
12144: if(dup_fd != -1) {
12145: REG16(AX) = dup_fd;
12146: msdos_file_handler_dup(dup_fd, fd, current_psp);
12147: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
12148: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
12149: } else {
12150: REG16(AX) = errno;
12151: m_CF = 1;
12152: }
12153: } else {
12154: REG16(AX) = 0x06;
12155: m_CF = 1;
12156: }
12157: }
12158:
12159: inline void msdos_int_21h_46h()
12160: {
12161: process_t *process = msdos_process_info_get(current_psp);
12162: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12163: int dup_fd = REG16(CX);
12164: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
12165:
12166: if(REG16(BX) == REG16(CX)) {
12167: REG16(AX) = 0x06;
12168: m_CF = 1;
12169: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
12170: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
12171: _close(tmp_fd);
12172: msdos_file_handler_close(tmp_fd);
12173: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
12174: }
12175: if(_dup2(fd, dup_fd) != -1) {
12176: msdos_file_handler_dup(dup_fd, fd, current_psp);
12177: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
12178: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
12179: } else {
12180: REG16(AX) = errno;
12181: m_CF = 1;
12182: }
12183: } else {
12184: REG16(AX) = 0x06;
12185: m_CF = 1;
12186: }
12187: }
12188:
12189: inline void msdos_int_21h_47h(int lfn)
12190: {
12191: char path[MAX_PATH];
12192:
12193: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
12194: if(!lfn) {
12195: strcpy(path, msdos_short_path(path));
12196: }
12197: if(path[1] == ':') {
12198: // the returned path does not include a drive or the initial backslash
12199: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path + 3);
12200: } else {
12201: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path);
12202: }
12203: } else {
12204: REG16(AX) = errno;
12205: m_CF = 1;
12206: }
12207: }
12208:
12209: inline void msdos_int_21h_48h()
12210: {
12211: int seg, umb_linked;
12212:
12213: if((malloc_strategy & 0xf0) == 0x00) {
12214: // unlink umb not to allocate memory in umb
12215: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
12216: msdos_mem_unlink_umb();
12217: }
12218: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
12219: REG16(AX) = seg;
12220: } else {
12221: REG16(AX) = 0x08;
12222: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
12223: m_CF = 1;
12224: }
12225: if(umb_linked != 0) {
12226: msdos_mem_link_umb();
12227: }
12228: } else if((malloc_strategy & 0xf0) == 0x40) {
12229: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
12230: REG16(AX) = seg;
12231: } else {
12232: REG16(AX) = 0x08;
12233: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
12234: m_CF = 1;
12235: }
12236: } else if((malloc_strategy & 0xf0) == 0x80) {
12237: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
12238: REG16(AX) = seg;
12239: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
12240: REG16(AX) = seg;
12241: } else {
12242: REG16(AX) = 0x08;
12243: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
12244: m_CF = 1;
12245: }
12246: }
12247: }
12248:
12249: inline void msdos_int_21h_49h()
12250: {
12251: int mcb_seg = SREG(ES) - 1;
12252: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
12253:
12254: if(mcb->mz == 'M' || mcb->mz == 'Z') {
12255: msdos_mem_free(SREG(ES));
12256: } else {
12257: REG16(AX) = 0x09; // illegal memory block address
12258: m_CF = 1;
12259: }
12260: }
12261:
12262: inline void msdos_int_21h_4ah()
12263: {
12264: int mcb_seg = SREG(ES) - 1;
12265: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
12266: int max_paragraphs;
12267:
12268: if(mcb->mz == 'M' || mcb->mz == 'Z') {
12269: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
12270: REG16(AX) = 0x08;
12271: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
12272: m_CF = 1;
12273: }
12274: } else {
12275: REG16(AX) = 0x09; // illegal memory block address
12276: m_CF = 1;
12277: }
12278: }
12279:
12280: inline void msdos_int_21h_4bh()
12281: {
12282: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
12283: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
12284:
12285: switch(REG8(AL)) {
12286: case 0x00:
12287: case 0x01:
12288: if(msdos_process_exec(command, param, REG8(AL))) {
12289: REG16(AX) = 0x02;
12290: m_CF = 1;
12291: }
12292: break;
12293: case 0x03:
12294: {
12295: int fd;
12296: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
12297: REG16(AX) = 0x02;
12298: m_CF = 1;
12299: break;
12300: }
12301: int size = _read(fd, file_buffer, sizeof(file_buffer));
12302: _close(fd);
12303:
12304: UINT16 *overlay = (UINT16 *)param;
12305:
12306: // check exe header
12307: exe_header_t *header = (exe_header_t *)file_buffer;
12308: int header_size = 0;
12309: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
12310: header_size = header->header_size * 16;
12311: // relocation
12312: int start_seg = overlay[1];
12313: for(int i = 0; i < header->relocations; i++) {
12314: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
12315: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
12316: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
12317: }
12318: }
12319: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
12320: }
12321: break;
12322: case 0x04:
12323: // Load And Execute In Background (European MS-DOS 4.0 only)
12324: // case 0x05:
12325: // // DOS 5+ - Set Execution State
12326: case 0x80:
12327: // DR DOS v3.41 - Run Already-Loaded Kernel File
12328: case 0xf0:
12329: case 0xf1:
12330: // DIET v1.10+
12331: case 0xfd:
12332: case 0xfe:
12333: // unknown function called in FreeCOM
12334: REG16(AX) = 0x01;
12335: m_CF = 1;
12336: break;
12337: default:
12338: 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));
12339: REG16(AX) = 0x01;
12340: m_CF = 1;
12341: break;
12342: }
12343: }
12344:
12345: inline void msdos_int_21h_4ch()
12346: {
12347: msdos_process_terminate(current_psp, REG8(AL), 1);
12348: }
12349:
12350: inline void msdos_int_21h_4dh()
12351: {
12352: REG16(AX) = retval;
12353: }
12354:
12355: inline void msdos_int_21h_4eh()
12356: {
12357: process_t *process = msdos_process_info_get(current_psp);
12358: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
12359: find_t *find = (find_t *)(mem + dta_laddr);
12360: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
12361: WIN32_FIND_DATAA fd;
12362:
12363: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
12364: find->find_magic = FIND_MAGIC;
12365: find->dta_index = dtainfo - dtalist;
12366: strcpy(process->volume_label, msdos_volume_label(path));
12367: dtainfo->allowable_mask = REG8(CL);
12368: // note: SO1 dir command sets 0x3f, but only directories and volue label are found if bit3 is set :-(
12369: if((dtainfo->allowable_mask & 0x3f) == 0x3f) {
12370: dtainfo->allowable_mask &= ~0x08;
12371: }
12372: bool label_only = (dtainfo->allowable_mask == 8);
12373:
12374: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
12375: dtainfo->allowable_mask &= ~8;
12376: }
12377: if(!label_only && (dtainfo->find_handle = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) {
12378: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
12379: !msdos_find_file_has_8dot3name(&fd)) {
12380: if(!FindNextFileA(dtainfo->find_handle, &fd)) {
12381: FindClose(dtainfo->find_handle);
12382: dtainfo->find_handle = INVALID_HANDLE_VALUE;
12383: break;
12384: }
12385: }
12386: }
12387: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12388: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
12389: msdos_find_file_conv_local_time(&fd);
12390: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
12391: find->size = fd.nFileSizeLow;
12392: strcpy(find->name, msdos_short_name(&fd));
12393: REG16(AX) = 0;
12394: } else if(dtainfo->allowable_mask & 8) {
12395: find->attrib = 8;
12396: find->size = 0;
12397: strcpy(find->name, msdos_short_volume_label(process->volume_label));
12398: dtainfo->allowable_mask &= ~8;
12399: REG16(AX) = 0;
12400: } else {
12401: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
12402: m_CF = 1;
12403: }
12404: }
12405:
12406: inline void msdos_int_21h_4fh()
12407: {
12408: process_t *process = msdos_process_info_get(current_psp);
12409: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
12410: find_t *find = (find_t *)(mem + dta_laddr);
12411: WIN32_FIND_DATAA fd;
12412:
12413: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
12414: REG16(AX) = 0x12;
12415: m_CF = 1;
12416: return;
12417: }
12418: dtainfo_t *dtainfo = &dtalist[find->dta_index];
12419: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12420: if(FindNextFileA(dtainfo->find_handle, &fd)) {
12421: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
12422: !msdos_find_file_has_8dot3name(&fd)) {
12423: if(!FindNextFileA(dtainfo->find_handle, &fd)) {
12424: FindClose(dtainfo->find_handle);
12425: dtainfo->find_handle = INVALID_HANDLE_VALUE;
12426: break;
12427: }
12428: }
12429: } else {
12430: FindClose(dtainfo->find_handle);
12431: dtainfo->find_handle = INVALID_HANDLE_VALUE;
12432: }
12433: }
12434: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12435: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
12436: msdos_find_file_conv_local_time(&fd);
12437: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
12438: find->size = fd.nFileSizeLow;
12439: strcpy(find->name, msdos_short_name(&fd));
12440: REG16(AX) = 0;
12441: } else if(dtainfo->allowable_mask & 8) {
12442: find->attrib = 8;
12443: find->size = 0;
12444: strcpy(find->name, msdos_short_volume_label(process->volume_label));
12445: dtainfo->allowable_mask &= ~8;
12446: REG16(AX) = 0;
12447: } else {
12448: REG16(AX) = 0x12;
12449: m_CF = 1;
12450: }
12451: }
12452:
12453: inline void msdos_int_21h_50h()
12454: {
12455: if(current_psp != REG16(BX)) {
12456: process_t *process = msdos_process_info_get(current_psp);
12457: if(process != NULL) {
12458: process->psp = REG16(BX);
12459: }
12460: current_psp = REG16(BX);
12461: msdos_sda_update(current_psp);
12462: }
12463: }
12464:
12465: inline void msdos_int_21h_51h()
12466: {
12467: REG16(BX) = current_psp;
12468: }
12469:
12470: inline void msdos_int_21h_52h()
12471: {
12472: SREG(ES) = DOS_INFO_TOP >> 4;
12473: i386_load_segment_descriptor(ES);
12474: REG16(BX) = offsetof(dos_info_t, first_dpb);
12475: }
12476:
12477: inline void msdos_int_21h_53h()
12478: {
12479: dpb_t *dpb = (dpb_t *)(mem + SREG_BASE(ES) + REG16(BP));
12480: bpb_t *bpb = (bpb_t *)(mem + SREG_BASE(DS) + REG16(SI));
12481:
12482: dpb->bytes_per_sector = bpb->bytes_per_sector;
12483: dpb->highest_sector_num = bpb->sectors_per_track - 1;
12484: dpb->shift_count = 0;
12485: dpb->reserved_sectors = 0;
12486: dpb->fat_num = bpb->fat_num;
12487: dpb->root_entries = bpb->root_entries;
12488: dpb->first_data_sector = 0;
12489: if(bpb->sectors_per_cluster != 0) {
12490: dpb->highest_cluster_num = (UINT16)(((REG16(CX) == 0x4558 && bpb->total_sectors == 0) ? bpb->ext_total_sectors : bpb->total_sectors) / bpb->sectors_per_cluster + 1);
12491: } else {
12492: dpb->highest_cluster_num = 0;
12493: }
12494: dpb->sectors_per_fat = (REG16(CX) == 0x4558 && bpb->sectors_per_fat == 0) ? bpb->ext_sectors_per_fat : bpb->sectors_per_fat;
12495: dpb->first_dir_sector = 0;
12496: dpb->device_driver_header = 0;
12497: dpb->media_type = bpb->media_type;
12498: dpb->drive_accessed = 0;
12499: dpb->next_dpb_ofs = 0xffff;
12500: dpb->next_dpb_seg = 0xffff;
12501: dpb->first_free_cluster = 0;
12502: dpb->free_clusters = 0xffff;
12503: }
12504:
12505: inline void msdos_int_21h_54h()
12506: {
12507: process_t *process = msdos_process_info_get(current_psp);
12508:
12509: REG8(AL) = process->verify;
12510: }
12511:
12512: inline void msdos_int_21h_55h()
12513: {
12514: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
12515:
12516: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
12517: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
12518: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
12519: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
12520: psp->parent_psp = current_psp;
12521: }
12522:
12523: inline void msdos_int_21h_56h(int lfn)
12524: {
12525: char src[MAX_PATH], dst[MAX_PATH];
12526: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
12527: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
12528:
12529: if(msdos_is_existing_file(dst) || msdos_is_existing_dir(dst)) {
12530: REG16(AX) = 0x05; // access denied
12531: m_CF = 1;
12532: } else if(rename(src, dst)) {
12533: REG16(AX) = errno;
12534: m_CF = 1;
12535: }
12536: }
12537:
12538: inline void msdos_int_21h_57h()
12539: {
12540: FILETIME time, local;
12541: FILETIME *ctime, *atime, *mtime;
12542: HANDLE hHandle;
12543:
12544: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
12545: REG16(AX) = (UINT16)GetLastError();
12546: m_CF = 1;
12547: return;
12548: }
12549: ctime = atime = mtime = NULL;
12550:
12551: switch(REG8(AL)) {
12552: case 0x00:
12553: case 0x01:
12554: mtime = &time;
12555: break;
12556: // case 0x02: // DOS 4.x only - Get Extended Attributes For File
12557: // case 0x03: // DOS 4.x only - Get Extended Attribute Properties
12558: // break;
12559: case 0x04:
12560: case 0x05:
12561: atime = &time;
12562: break;
12563: case 0x06:
12564: case 0x07:
12565: ctime = &time;
12566: break;
12567: default:
12568: 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));
12569: REG16(AX) = 0x01;
12570: m_CF = 1;
12571: return;
12572: }
12573: if(REG8(AL) & 1) {
12574: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
12575: LocalFileTimeToFileTime(&local, &time);
12576: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
12577: REG16(AX) = (UINT16)GetLastError();
12578: m_CF = 1;
12579: }
12580: } else {
12581: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
12582: // assume a device and use the current time
12583: GetSystemTimeAsFileTime(&time);
12584: }
12585: FileTimeToLocalFileTime(&time, &local);
12586: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
12587: }
12588: }
12589:
12590: inline void msdos_int_21h_58h()
12591: {
12592: switch(REG8(AL)) {
12593: case 0x00:
12594: REG16(AX) = malloc_strategy;
12595: break;
12596: case 0x01:
12597: // switch(REG16(BX)) {
12598: switch(REG8(BL)) {
12599: case 0x0000:
12600: case 0x0001:
12601: case 0x0002:
12602: case 0x0040:
12603: case 0x0041:
12604: case 0x0042:
12605: case 0x0080:
12606: case 0x0081:
12607: case 0x0082:
12608: malloc_strategy = REG16(BX);
12609: msdos_sda_update(current_psp);
12610: break;
12611: default:
12612: 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));
12613: REG16(AX) = 0x01;
12614: m_CF = 1;
12615: break;
12616: }
12617: break;
12618: case 0x02:
12619: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
12620: break;
12621: case 0x03:
12622: // switch(REG16(BX)) {
12623: switch(REG8(BL)) {
12624: case 0x0000:
12625: msdos_mem_unlink_umb();
12626: break;
12627: case 0x0001:
12628: msdos_mem_link_umb();
12629: break;
12630: default:
12631: 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));
12632: REG16(AX) = 0x01;
12633: m_CF = 1;
12634: break;
12635: }
12636: break;
12637: default:
12638: 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));
12639: REG16(AX) = 0x01;
12640: m_CF = 1;
12641: break;
12642: }
12643: }
12644:
12645: inline void msdos_int_21h_59h()
12646: {
12647: if(REG16(BX) == 0x0000) {
12648: sda_t *sda = (sda_t *)(mem + SDA_TOP);
12649:
12650: REG16(AX) = sda->extended_error_code;
12651: REG8(BH) = sda->error_class;
12652: REG8(BL) = sda->suggested_action;
12653: REG8(CH) = sda->locus_of_last_error;
12654: // XXX: GW-BASIC 3.23 invites the registers contents of CL, DX, SI, DI, DS, and ES are not destroyed
12655: if(sda->int21h_5d0ah_called != 0) {
12656: REG8(CL) = sda->int21h_5d0ah_cl;
12657: REG16(DX) = sda->int21h_5d0ah_dx;
12658: // REG16(SI) = sda->int21h_5d0ah_si;
12659: REG16(DI) = sda->last_error_pointer.w.l;
12660: // SREG(DS) = sda->int21h_5d0ah_ds;
12661: // i386_load_segment_descriptor(DS);
12662: SREG(ES) = sda->last_error_pointer.w.h;
12663: i386_load_segment_descriptor(ES);
12664: }
12665: sda->int21h_5d0ah_called = 0;
12666: // } else if(REG16(BX) == 0x0001) {
12667: // // European MS-DOS 4.0 - Get Hard Error Information
12668: } else {
12669: 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));
12670: REG16(AX) = 0x01;
12671: m_CF = 1;
12672: }
12673: }
12674:
12675: inline void msdos_int_21h_5ah()
12676: {
12677: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
12678: int len = strlen(path);
12679: char tmp[MAX_PATH];
12680:
12681: if(GetTempFileNameA(path, "TMP", 0, tmp)) {
12682: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
12683:
12684: SetFileAttributesA(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
12685: REG16(AX) = fd;
12686: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
12687: msdos_psp_set_file_table(fd, fd, current_psp);
12688:
12689: strcpy(path, tmp);
12690: int dx = REG16(DX) + len;
12691: int ds = SREG(DS);
12692: while(dx > 0xffff) {
12693: dx -= 0x10;
12694: ds++;
12695: }
12696: REG16(DX) = dx;
12697: SREG(DS) = ds;
12698: i386_load_segment_descriptor(DS);
12699: } else {
12700: REG16(AX) = (UINT16)GetLastError();
12701: m_CF = 1;
12702: }
12703: }
12704:
12705: inline void msdos_int_21h_5bh()
12706: {
12707: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
12708:
12709: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
12710: // already exists
12711: REG16(AX) = 0x50;
12712: m_CF = 1;
12713: } else {
12714: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
12715:
12716: if(fd != -1) {
12717: SetFileAttributesA(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
12718: REG16(AX) = fd;
12719: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
12720: msdos_psp_set_file_table(fd, fd, current_psp);
12721: } else {
12722: REG16(AX) = errno;
12723: m_CF = 1;
12724: }
12725: }
12726: }
12727:
12728: inline void msdos_int_21h_5ch()
12729: {
12730: process_t *process = msdos_process_info_get(current_psp);
12731: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12732:
12733: if(fd < process->max_files && file_handler[fd].valid) {
12734: if(REG8(AL) == 0 || REG8(AL) == 1) {
12735: static const int modes[2] = {_LK_LOCK, _LK_UNLCK};
12736: UINT32 pos = _tell(fd);
12737: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
12738: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
12739: REG16(AX) = errno;
12740: m_CF = 1;
12741: }
12742: _lseek(fd, pos, SEEK_SET);
12743:
12744: // some seconds may be passed in _locking()
12745: REQUEST_HARDWRE_UPDATE();
12746: } else {
12747: REG16(AX) = 0x01;
12748: m_CF = 1;
12749: }
12750: } else {
12751: REG16(AX) = 0x06;
12752: m_CF = 1;
12753: }
12754: }
12755:
12756: inline void msdos_int_21h_5dh()
12757: {
12758: switch(REG8(AL)) {
12759: case 0x00: // DOS 3.1+ internal - Server Function Call
12760: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x12) == 0x0000) {
12761: // current system
12762: static bool reenter = false;
12763: if(!reenter) {
12764: UINT32 offset = SREG_BASE(DS) + REG16(DX);
12765: REG16(AX) = *(UINT16 *)(mem + offset + 0x00);
12766: REG16(BX) = *(UINT16 *)(mem + offset + 0x02);
12767: REG16(CX) = *(UINT16 *)(mem + offset + 0x04);
12768: REG16(DX) = *(UINT16 *)(mem + offset + 0x06);
12769: REG16(SI) = *(UINT16 *)(mem + offset + 0x08);
12770: REG16(DI) = *(UINT16 *)(mem + offset + 0x0a);
12771: SREG(DS) = *(UINT16 *)(mem + offset + 0x0c);
12772: SREG(ES) = *(UINT16 *)(mem + offset + 0x0e);
12773: i386_load_segment_descriptor(DS);
12774: i386_load_segment_descriptor(ES);
12775: reenter = true;
12776: try {
12777: msdos_syscall(0x21);
12778: } catch(...) {
12779: }
12780: reenter = false;
12781: }
12782: } else {
12783: REG16(AX) = 0x49; // network software not installed
12784: m_CF = 1;
12785: }
12786: break;
12787: // case 0x01: // DOS 3.1+ internal - Commit All Files For Specified Computer/Process
12788: // case 0x02: // DOS 3.1+ internal - SHARE.EXE - Close File By Name
12789: // case 0x03: // DOS 3.1+ internal - SHARE.EXE - Close ALL Files For Given Computer
12790: // case 0x04: // DOS 3.1+ internal - SHARE.EXE - Close ALL Files For Given Process
12791: // case 0x05: // DOS 3.1+ internal - SHARE.EXE - Get Open File List Entry
12792: case 0x06: // DOS 3.0+ internal - Get Address Of DOS Swappable Data Area
12793: SREG(DS) = (SDA_TOP >> 4);
12794: i386_load_segment_descriptor(DS);
12795: REG16(SI) = offsetof(sda_t, crit_error_flag);
12796: REG16(CX) = 0x80;
12797: REG16(DX) = 0x1a;
12798: break;
12799: case 0x07: // DOS 3.1+ network - Get Redirected Printer Mode
12800: case 0x08: // DOS 3.1+ network - Set Redirected Printer Mode
12801: case 0x09: // DOS 3.1+ network - Flush Redirected Printer Output
12802: REG16(AX) = 0x49; // network software not installed
12803: m_CF = 1;
12804: break;
12805: case 0x0a: // DOS 3.1+ - Set Extended Error Information
12806: {
12807: sda_t *sda = (sda_t *)(mem + SDA_TOP);
12808: sda->int21h_5d0ah_called = 1;
12809: sda->extended_error_code = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00); // AX
12810: // XXX: which one is correct ???
12811: #if 1
12812: // Ralf Brown's Interrupt List and DR-DOS System and Programmer's Guide
12813: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BL
12814: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BH
12815: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CL
12816: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CH
12817: #else
12818: // PC DOS 7 Technical Update
12819: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BH
12820: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BL
12821: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CH
12822: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CL
12823: #endif
12824: sda->int21h_5d0ah_dx = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06); // DX
12825: // sda->int21h_5d0ah_si = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08); // SI
12826: sda->last_error_pointer.w.l = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a); // DI
12827: // sda->int21h_5d0ah_ds = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c); // DS
12828: sda->last_error_pointer.w.h = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // ES
12829: }
12830: break;
12831: case 0x0b: // DOS 4.x only - internal - Get DOS Swappable Data Areas
12832: REG16(AX) = 0x01;
12833: m_CF = 1;
12834: break;
12835: default:
12836: 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));
12837: REG16(AX) = 0x01;
12838: m_CF = 1;
12839: break;
12840: }
12841: }
12842:
12843: inline void msdos_int_21h_5eh()
12844: {
12845: switch(REG8(AL)) {
12846: case 0x00: // DOS 3.1+ network - Get Machine Name
12847: {
12848: char name[256] = {0};
12849: DWORD dwSize = 256;
12850:
12851: if(GetComputerNameA(name, &dwSize)) {
12852: char *dest = (char *)(mem + SREG_BASE(DS) + REG16(DX));
12853: for(int i = 0; i < 15; i++) {
12854: dest[i] = (i < strlen(name)) ? name[i] : ' ';
12855: }
12856: dest[15] = '\0';
12857: REG8(CH) = 0x01; // nonzero valid
12858: REG8(CL) = 0x01; // NetBIOS number for machine name ???
12859: } else {
12860: REG16(AX) = 0x01;
12861: m_CF = 1;
12862: }
12863: }
12864: break;
12865: // case 0x01: // DOS 3.1+ network - Set Machine Name
12866: // case 0x02: // DOS 3.1+ network - Set Network Printer Setup String
12867: // case 0x03: // DOS 3.1+ network - Get Network Printer Setup String
12868: // case 0x04: // DOS 3.1+ network - Set Printer Mode
12869: // case 0x05: // DOS 3.1+ network - Get Printer Mode
12870: default:
12871: // 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));
12872: // REG16(AX) = 0x01;
12873: REG16(AX) = 0x49; // network software not installed
12874: m_CF = 1;
12875: break;
12876: }
12877: }
12878:
12879: inline void msdos_int_21h_5fh()
12880: {
12881: switch(REG8(AL)) {
12882: // case 0x00: // DOS 3.1+ network - Get Redirection Mode
12883: // case 0x01: // DOS 3.1+ network - Set Redirection Mode
12884: case 0x05: // DOS 4.0+ network - Get Extended Redirection List Entry
12885: REG16(BP) = 0;
12886: for(int i = 0; i < 26; i++) {
12887: if(msdos_is_remote_drive(i)) {
12888: REG16(BP)++;
12889: }
12890: }
12891: case 0x02: // DOS 3.1+ network - Get Redirection List Entry
12892: for(int i = 0, index = 0; i < 26; i++) {
12893: if(msdos_is_remote_drive(i)) {
12894: if(index == REG16(BX)) {
12895: char volume[] = "A:";
12896: volume[0] = 'A' + i;
12897: DWORD dwSize = 128;
12898: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
12899: WNetGetConnectionA(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
12900: REG8(BH) = 0x00; // valid
12901: REG8(BL) = 0x04; // disk drive
12902: REG16(CX) = 0x00; // LANtastic
12903: return;
12904: }
12905: index++;
12906: }
12907: }
12908: REG16(AX) = 0x12; // no more files
12909: m_CF = 1;
12910: break;
12911: // case 0x03: // DOS 3.1+ network - Redirect Device
12912: // case 0x04: // DOS 3.1+ network - Cancel Redirection
12913: // case 0x06: // Network - Get Full Redirection List
12914: case 0x07: // DOS 5+ - Enable Drive
12915: if(msdos_is_valid_drive(REG8(DL))) {
12916: msdos_cds_update(REG8(DL));
12917: } else {
12918: REG16(AX) = 0x0f; // invalid drive
12919: m_CF = 1;
12920: }
12921: break;
12922: case 0x08: // DOS 5+ - Disable Drive
12923: if(msdos_is_valid_drive(REG8(DL))) {
12924: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * REG8(DL));
12925: cds->drive_attrib = 0x0000;
12926: } else {
12927: REG16(AX) = 0x0f; // invalid drive
12928: m_CF = 1;
12929: }
12930: break;
12931: default:
12932: // 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));
12933: // REG16(AX) = 0x01;
12934: REG16(AX) = 0x49; // network software not installed
12935: m_CF = 1;
12936: break;
12937: }
12938: }
12939:
12940: inline void msdos_int_21h_60h(int lfn)
12941: {
12942: char full[MAX_PATH];
12943: const char *path = NULL;
12944:
12945: if(lfn) {
12946: char *name;
12947: *full = '\0';
12948: GetFullPathNameA((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
12949: switch(REG8(CL)) {
12950: case 1:
12951: GetShortPathNameA(full, full, MAX_PATH);
12952: my_strupr(full);
12953: break;
12954: case 2:
12955: GetLongPathNameA(full, full, MAX_PATH);
12956: break;
12957: }
12958: path = full;
12959: } else {
12960: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
12961: }
12962: if(*path != '\0') {
12963: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
12964: } else {
12965: REG16(AX) = (UINT16)GetLastError();
12966: m_CF = 1;
12967: }
12968: }
12969:
12970: inline void msdos_int_21h_61h()
12971: {
12972: REG8(AL) = 0;
12973: }
12974:
12975: inline void msdos_int_21h_62h()
12976: {
12977: REG16(BX) = current_psp;
12978: }
12979:
12980: inline void msdos_int_21h_63h()
12981: {
12982: switch(REG8(AL)) {
12983: case 0x00:
12984: SREG(DS) = (DBCS_TABLE >> 4);
12985: i386_load_segment_descriptor(DS);
12986: REG16(SI) = (DBCS_TABLE & 0x0f);
12987: REG8(AL) = 0x00;
12988: break;
12989: case 0x01: // set korean input mode
12990: case 0x02: // get korean input mode
12991: REG8(AL) = 0xff; // not supported
12992: break;
12993: default:
12994: 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));
12995: REG16(AX) = 0x01;
12996: m_CF = 1;
12997: break;
12998: }
12999: }
13000:
13001: UINT16 get_extended_country_info(UINT8 func)
13002: {
13003: switch(func) {
13004: case 0x01:
13005: if(REG16(CX) >= 5) {
13006: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
13007: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
13008: REG16(CX) = sizeof(data);
13009: ZeroMemory(data, sizeof(data));
13010: data[0] = 0x01;
13011: *(UINT16 *)(data + 1) = REG16(CX) - 3;
13012: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
13013: *(UINT16 *)(data + 5) = active_code_page;
13014: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
13015: // REG16(AX) = active_code_page;
13016: } else {
13017: return(0x08); // insufficient memory
13018: }
13019: break;
13020: case 0x02:
13021: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
13022: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
13023: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
13024: // REG16(AX) = active_code_page;
13025: REG16(CX) = 0x05;
13026: break;
13027: case 0x03:
13028: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
13029: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
13030: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
13031: // REG16(AX) = active_code_page;
13032: REG16(CX) = 0x05;
13033: break;
13034: case 0x04:
13035: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
13036: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
13037: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
13038: // REG16(AX) = active_code_page;
13039: REG16(CX) = 0x05;
13040: break;
13041: case 0x05:
13042: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
13043: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
13044: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
13045: // REG16(AX) = active_code_page;
13046: REG16(CX) = 0x05;
13047: break;
13048: case 0x06:
13049: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
13050: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
13051: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
13052: // REG16(AX) = active_code_page;
13053: REG16(CX) = 0x05;
13054: break;
13055: case 0x07:
13056: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
13057: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
13058: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
13059: // REG16(AX) = active_code_page;
13060: REG16(CX) = 0x05;
13061: break;
13062: default:
13063: return(0x01); // function number invalid
13064: }
13065: return(0x00);
13066: }
13067:
13068: inline void msdos_int_21h_65h()
13069: {
13070: char tmp[0x10000];
13071:
13072: switch(REG8(AL)) {
13073: case 0x00:
13074: if(REG16(CX) >= 7) {
13075: set_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), REG16(CX) - 7);
13076: REG16(AX) = system_code_page;
13077: } else {
13078: REG16(AX) = 0x0c;
13079: m_CF = 1;
13080: }
13081: break;
13082: case 0x01:
13083: case 0x02:
13084: case 0x03:
13085: case 0x04:
13086: case 0x05:
13087: case 0x06:
13088: case 0x07:
13089: {
13090: UINT16 result = get_extended_country_info(REG8(AL));
13091: if(result) {
13092: REG16(AX) = result;
13093: m_CF = 1;
13094: } else {
13095: REG16(AX) = active_code_page; // FIXME: is this correct???
13096: }
13097: }
13098: break;
13099: case 0x20:
13100: case 0xa0:
13101: memset(tmp, 0, sizeof(tmp));
13102: tmp[0] = REG8(DL);
13103: my_strupr(tmp);
13104: REG8(DL) = tmp[0];
13105: break;
13106: case 0x21:
13107: case 0xa1:
13108: memset(tmp, 0, sizeof(tmp));
13109: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
13110: my_strupr(tmp);
13111: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
13112: break;
13113: case 0x22:
13114: case 0xa2:
13115: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
13116: break;
13117: case 0x23:
13118: // FIXME: need to check multi-byte (kanji) charactre?
13119: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
13120: // 826dh/828eh: multi-byte (kanji) N and n
13121: REG16(AX) = 0x00;
13122: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
13123: // 8278h/8299h: multi-byte (kanji) Y and y
13124: REG16(AX) = 0x01;
13125: } else {
13126: REG16(AX) = 0x02;
13127: }
13128: break;
13129: default:
13130: 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));
13131: REG16(AX) = 0x01;
13132: m_CF = 1;
13133: break;
13134: }
13135: }
13136:
13137: inline void msdos_int_21h_66h()
13138: {
13139: switch(REG8(AL)) {
13140: case 0x01:
13141: REG16(BX) = active_code_page;
13142: REG16(DX) = system_code_page;
13143: break;
13144: case 0x02:
13145: if(active_code_page == REG16(BX)) {
13146: REG16(AX) = 0xeb41;
13147: } else if(_setmbcp(REG16(BX)) == 0) {
13148: active_code_page = REG16(BX);
13149: msdos_nls_tables_update();
13150: REG16(AX) = 0xeb41;
13151: SetConsoleCP(active_code_page);
13152: SetConsoleOutputCP(active_code_page);
13153: } else {
13154: REG16(AX) = 0x25;
13155: m_CF = 1;
13156: }
13157: break;
13158: default:
13159: 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));
13160: REG16(AX) = 0x01;
13161: m_CF = 1;
13162: break;
13163: }
13164: }
13165:
13166: inline void msdos_int_21h_67h()
13167: {
13168: process_t *process = msdos_process_info_get(current_psp);
13169:
13170: if(REG16(BX) <= MAX_FILES) {
13171: process->max_files = max(REG16(BX), 20);
13172: } else {
13173: REG16(AX) = 0x08;
13174: m_CF = 1;
13175: }
13176: }
13177:
13178: inline void msdos_int_21h_68h()
13179: {
13180: process_t *process = msdos_process_info_get(current_psp);
13181: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
13182:
13183: if(fd < process->max_files && file_handler[fd].valid) {
13184: // fflush(_fdopen(fd, ""));
13185: } else {
13186: REG16(AX) = 0x06;
13187: m_CF = 1;
13188: }
13189: }
13190:
13191: inline void msdos_int_21h_69h()
13192: {
13193: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
13194: char path[] = "A:\\";
13195: char volume_label[MAX_PATH];
13196: DWORD serial_number = 0;
13197: char file_system[MAX_PATH];
13198:
13199: if(REG8(BL) == 0) {
13200: path[0] = 'A' + _getdrive() - 1;
13201: } else {
13202: path[0] = 'A' + REG8(BL) - 1;
13203: }
13204:
13205: switch(REG8(AL)) {
13206: case 0x00:
13207: if(GetVolumeInformationA(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
13208: info->info_level = 0;
13209: info->serial_number = serial_number;
13210: memset(info->volume_label, 0x20, 11);
13211: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
13212: memset(info->file_system, 0x20, 8);
13213: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
13214: } else {
13215: REG16(AX) = errno;
13216: m_CF = 1;
13217: }
13218: break;
13219: case 0x01:
13220: REG16(AX) = 0x03;
13221: m_CF = 1;
13222: break;
13223: default:
13224: 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));
13225: REG16(AX) = 0x01;
13226: m_CF = 1;
13227: break;
13228: }
13229: }
13230:
13231: inline void msdos_int_21h_6ah()
13232: {
13233: REG8(AH) = 0x68;
13234: msdos_int_21h_68h();
13235: }
13236:
13237: inline void msdos_int_21h_6bh()
13238: {
13239: REG8(AL) = 0x00;
13240: }
13241:
13242: inline void msdos_int_21h_6ch(int lfn)
13243: {
13244: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
13245: int mode = REG8(BL) & 0x03;
13246:
13247: if(mode < 0x03) {
13248: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
13249: // file exists
13250: if(REG8(DL) & 1) {
13251: int fd = -1;
13252: int sio_port = 0;
13253: int lpt_port = 0;
13254:
13255: if(msdos_is_device_path(path)) {
13256: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
13257: } else {
13258: fd = msdos_open(path, file_mode[mode].mode);
13259: }
13260: if(fd != -1) {
13261: REG16(AX) = fd;
13262: REG16(CX) = 1;
13263: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port);
13264: msdos_psp_set_file_table(fd, fd, current_psp);
13265: } else {
13266: REG16(AX) = errno;
13267: m_CF = 1;
13268: }
13269: } else if(REG8(DL) & 2) {
13270: int attr = GetFileAttributesA(path);
13271: int fd = -1;
13272: int sio_port = 0;
13273: int lpt_port = 0;
13274:
13275: if(msdos_is_device_path(path)) {
13276: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
13277: } else {
13278: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
13279: }
13280: if(fd != -1) {
13281: if(attr == -1) {
13282: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
13283: }
13284: SetFileAttributesA(path, attr);
13285: REG16(AX) = fd;
13286: REG16(CX) = 3;
13287: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port);
13288: msdos_psp_set_file_table(fd, fd, current_psp);
13289: } else {
13290: REG16(AX) = errno;
13291: m_CF = 1;
13292: }
13293: } else {
13294: REG16(AX) = 0x50;
13295: m_CF = 1;
13296: }
13297: } else {
13298: // file not exists
13299: if(REG8(DL) & 0x10) {
13300: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
13301:
13302: if(fd != -1) {
13303: SetFileAttributesA(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
13304: REG16(AX) = fd;
13305: REG16(CX) = 2;
13306: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
13307: msdos_psp_set_file_table(fd, fd, current_psp);
13308: } else {
13309: REG16(AX) = errno;
13310: m_CF = 1;
13311: }
13312: } else {
13313: REG16(AX) = 0x02;
13314: m_CF = 1;
13315: }
13316: }
13317: } else {
13318: REG16(AX) = 0x0c;
13319: m_CF = 1;
13320: }
13321: }
13322:
13323: inline void msdos_int_21h_70h()
13324: {
13325: switch(REG8(AL)) {
13326: case 0x00: // get ??? info
13327: case 0x01: // set above info
13328: // 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));
13329: REG16(AX) = 0x7000;
13330: m_CF = 1;
13331: break;
13332: case 0x02: // set general internationalization info
13333: if(REG16(CX) >= 7) {
13334: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
13335: msdos_nls_tables_update();
13336: set_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(SI) + 7), REG16(CX) - 7);
13337: REG16(AX) = system_code_page;
13338: } else {
13339: REG16(AX) = 0x0c;
13340: m_CF = 1;
13341: }
13342: break;
13343: default:
13344: 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));
13345: REG16(AX) = 0x7000;
13346: m_CF = 1;
13347: break;
13348: }
13349: }
13350:
13351: inline void msdos_int_21h_710dh()
13352: {
13353: // reset drive
13354: }
13355:
13356: inline void msdos_int_21h_7141h()
13357: {
13358: if(REG16(SI) == 0) {
13359: msdos_int_21h_41h(1);
13360: return;
13361: }
13362: if(REG16(SI) != 1) {
13363: REG16(AX) = 5;
13364: m_CF = 1;
13365: }
13366: /* wild card and matching attributes... */
13367: char tmp[MAX_PATH * 2];
13368: // copy search pathname (and quick check overrun)
13369: ZeroMemory(tmp, sizeof(tmp));
13370: tmp[MAX_PATH - 1] = '\0';
13371: tmp[MAX_PATH] = 1;
13372: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
13373:
13374: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
13375: REG16(AX) = 1;
13376: m_CF = 1;
13377: return;
13378: }
13379: for(char *s = tmp; *s; ++s) {
13380: if(*s == '/') {
13381: *s = '\\';
13382: }
13383: }
13384: char *tmp_name = my_strrchr(tmp, '\\');
13385: if(tmp_name) {
13386: ++tmp_name;
13387: } else {
13388: tmp_name = strchr(tmp, ':');
13389: tmp_name = tmp_name ? tmp_name + 1 : tmp;
13390: }
13391:
13392: WIN32_FIND_DATAA fd;
13393: HANDLE fh = FindFirstFileA(tmp, &fd);
13394: if(fh == INVALID_HANDLE_VALUE) {
13395: REG16(AX) = 2;
13396: m_CF = 1;
13397: return;
13398: }
13399: do {
13400: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
13401: strcpy(tmp_name, fd.cFileName);
13402: if(remove(msdos_trimmed_path(tmp, 1))) {
13403: REG16(AX) = 5;
13404: m_CF = 1;
13405: break;
13406: }
13407: }
13408: } while(FindNextFileA(fh, &fd));
13409: if(!m_CF) {
13410: if(GetLastError() != ERROR_NO_MORE_FILES) {
13411: m_CF = 1;
13412: REG16(AX) = 2;
13413: }
13414: }
13415: FindClose(fh);
13416: }
13417:
13418: inline void msdos_int_21h_714eh()
13419: {
13420: process_t *process = msdos_process_info_get(current_psp);
13421: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
13422: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
13423: WIN32_FIND_DATAA fd;
13424:
13425: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
13426: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
13427: FindClose(dtainfo->find_handle);
13428: dtainfo->find_handle = INVALID_HANDLE_VALUE;
13429: }
13430: strcpy(process->volume_label, msdos_volume_label(path));
13431: dtainfo->allowable_mask = REG8(CL);
13432: dtainfo->required_mask = REG8(CH);
13433: bool label_only = (dtainfo->allowable_mask == 8);
13434:
13435: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
13436: dtainfo->allowable_mask &= ~8;
13437: }
13438: if(!label_only && (dtainfo->find_handle = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) {
13439: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
13440: if(!FindNextFileA(dtainfo->find_handle, &fd)) {
13441: FindClose(dtainfo->find_handle);
13442: dtainfo->find_handle = INVALID_HANDLE_VALUE;
13443: break;
13444: }
13445: }
13446: }
13447: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
13448: find->attrib = fd.dwFileAttributes;
13449: msdos_find_file_conv_local_time(&fd);
13450: if(REG16(SI) == 0) {
13451: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
13452: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
13453: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
13454: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
13455: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
13456: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
13457: } else {
13458: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
13459: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
13460: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
13461: }
13462: find->size_hi = fd.nFileSizeHigh;
13463: find->size_lo = fd.nFileSizeLow;
13464: strcpy(find->full_name, fd.cFileName);
13465: strcpy(find->short_name, fd.cAlternateFileName);
13466: REG16(AX) = dtainfo - dtalist + 1;
13467: } else if(dtainfo->allowable_mask & 8) {
13468: // volume label
13469: find->attrib = 8;
13470: find->size_hi = find->size_lo = 0;
13471: strcpy(find->full_name, process->volume_label);
13472: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
13473: dtainfo->allowable_mask &= ~8;
13474: REG16(AX) = dtainfo - dtalist + 1;
13475: } else {
13476: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
13477: m_CF = 1;
13478: }
13479: }
13480:
13481: inline void msdos_int_21h_714fh()
13482: {
13483: process_t *process = msdos_process_info_get(current_psp);
13484: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
13485: WIN32_FIND_DATAA fd;
13486:
13487: if(REG16(BX) - 1u >= MAX_DTAINFO) {
13488: REG16(AX) = 6;
13489: m_CF = 1;
13490: return;
13491: }
13492: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
13493: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
13494: if(FindNextFileA(dtainfo->find_handle, &fd)) {
13495: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
13496: if(!FindNextFileA(dtainfo->find_handle, &fd)) {
13497: FindClose(dtainfo->find_handle);
13498: dtainfo->find_handle = INVALID_HANDLE_VALUE;
13499: break;
13500: }
13501: }
13502: } else {
13503: FindClose(dtainfo->find_handle);
13504: dtainfo->find_handle = INVALID_HANDLE_VALUE;
13505: }
13506: }
13507: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
13508: find->attrib = fd.dwFileAttributes;
13509: msdos_find_file_conv_local_time(&fd);
13510: if(REG16(SI) == 0) {
13511: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
13512: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
13513: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
13514: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
13515: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
13516: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
13517: } else {
13518: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
13519: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
13520: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
13521: }
13522: find->size_hi = fd.nFileSizeHigh;
13523: find->size_lo = fd.nFileSizeLow;
13524: strcpy(find->full_name, fd.cFileName);
13525: strcpy(find->short_name, fd.cAlternateFileName);
13526: } else if(dtainfo->allowable_mask & 8) {
13527: // volume label
13528: find->attrib = 8;
13529: find->size_hi = find->size_lo = 0;
13530: strcpy(find->full_name, process->volume_label);
13531: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
13532: dtainfo->allowable_mask &= ~8;
13533: } else {
13534: REG16(AX) = 0x12;
13535: m_CF = 1;
13536: }
13537: }
13538:
13539: inline void msdos_int_21h_71a0h()
13540: {
13541: DWORD max_component_len, file_sys_flag;
13542:
13543: if(GetVolumeInformationA((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))) {
13544: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
13545: REG16(BX) |= 0x4000; // supports LFN functions
13546: REG16(CX) = (UINT16)max_component_len; // 255
13547: REG16(DX) = (UINT16)max_component_len + 5; // 260
13548: } else {
13549: REG16(AX) = (UINT16)GetLastError();
13550: m_CF = 1;
13551: }
13552: }
13553:
13554: inline void msdos_int_21h_71a1h()
13555: {
13556: if(REG16(BX) - 1u >= MAX_DTAINFO) {
13557: REG16(AX) = 6;
13558: m_CF = 1;
13559: return;
13560: }
13561: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
13562: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
13563: FindClose(dtainfo->find_handle);
13564: dtainfo->find_handle = INVALID_HANDLE_VALUE;
13565: }
13566: }
13567:
13568: inline void msdos_int_21h_71a6h()
13569: {
13570: process_t *process = msdos_process_info_get(current_psp);
13571: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
13572:
13573: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
13574: struct _stat64 status;
13575: DWORD serial_number = 0;
13576:
13577: if(fd < process->max_files && file_handler[fd].valid) {
13578: if(_fstat64(fd, &status) == 0) {
13579: if(file_handler[fd].path[1] == ':') {
13580: // NOTE: we need to consider the network file path "\\host\share\"
13581: char volume[] = "A:\\";
13582: volume[0] = file_handler[fd].path[1];
13583: GetVolumeInformationA(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
13584: }
13585: *(UINT32 *)(buffer + 0x00) = GetFileAttributesA(file_handler[fd].path);
13586: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
13587: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
13588: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
13589: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
13590: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
13591: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
13592: *(UINT32 *)(buffer + 0x1c) = serial_number;
13593: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
13594: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
13595: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
13596: // this is dummy id and it will be changed when it is reopened...
13597: *(UINT32 *)(buffer + 0x2c) = 0;
13598: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
13599: } else {
13600: REG16(AX) = errno;
13601: m_CF = 1;
13602: }
13603: } else {
13604: REG16(AX) = 0x06;
13605: m_CF = 1;
13606: }
13607: }
13608:
13609: inline void msdos_int_21h_71a7h()
13610: {
13611: switch(REG8(BL)) {
13612: case 0x00:
13613: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
13614: REG16(AX) = (UINT16)GetLastError();
13615: m_CF = 1;
13616: }
13617: break;
13618: case 0x01:
13619: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
13620: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
13621: REG16(AX) = (UINT16)GetLastError();
13622: m_CF = 1;
13623: }
13624: break;
13625: default:
13626: 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));
13627: REG16(AX) = 0x7100;
13628: m_CF = 1;
13629: break;
13630: }
13631: }
13632:
13633: inline void msdos_int_21h_71a8h()
13634: {
13635: if(REG8(DH) == 0) {
13636: char tmp[MAX_PATH], fcb[MAX_PATH];
13637: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
13638: memset(fcb, 0x20, sizeof(fcb));
13639: int len = strlen(tmp);
13640: for(int i = 0, pos = 0; i < len; i++) {
13641: if(tmp[i] == '.') {
13642: pos = 8;
13643: } else {
13644: if(msdos_lead_byte_check(tmp[i])) {
13645: fcb[pos++] = tmp[i++];
13646: }
13647: fcb[pos++] = tmp[i];
13648: }
13649: }
13650: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
13651: } else {
13652: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
13653: }
13654: }
13655:
13656: inline void msdos_int_21h_71aah()
13657: {
13658: char drv[] = "A:", path[MAX_PATH];
13659: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
13660:
13661: if(REG8(BL) == 0) {
13662: drv[0] = 'A' + _getdrive() - 1;
13663: } else {
13664: drv[0] = 'A' + REG8(BL) - 1;
13665: }
13666: switch(REG8(BH)) {
13667: case 0x00:
13668: if(msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
13669: REG16(AX) = 0x0f; // invalid drive
13670: m_CF = 1;
13671: } else if(DefineDosDeviceA(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
13672: REG16(AX) = 0x03; // path not found
13673: m_CF = 1;
13674: }
13675: break;
13676: case 0x01:
13677: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
13678: REG16(AX) = 0x0f; // invalid drive
13679: m_CF = 1;
13680: } else if(DefineDosDeviceA(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
13681: REG16(AX) = 0x0f; // invalid drive
13682: m_CF = 1;
13683: }
13684: break;
13685: case 0x02:
13686: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
13687: REG16(AX) = 0x0f; // invalid drive
13688: m_CF = 1;
13689: } else if(QueryDosDeviceA(drv, path, MAX_PATH) == 0) {
13690: REG16(AX) = 0x0f; // invalid drive
13691: m_CF = 1;
13692: } else if(strncmp(path, "\\??\\", 4) != 0) {
13693: REG16(AX) = 0x0f; // invalid drive
13694: m_CF = 1;
13695: } else {
13696: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
13697: }
13698: break;
13699: default:
13700: 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));
13701: REG16(AX) = 0x7100;
13702: m_CF = 1;
13703: break;
13704: }
13705: }
13706:
13707: inline void msdos_int_21h_7300h()
13708: {
13709: REG8(AL) = REG8(CL);
13710: REG8(AH) = 0;
13711: }
13712:
13713: inline void msdos_int_21h_7302h()
13714: {
13715: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
13716: UINT16 seg, ofs;
13717:
13718: if(REG16(CX) < 0x3f) {
13719: REG8(AL) = 0x18;
13720: m_CF = 1;
13721: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
13722: REG8(AL) = 0xff;
13723: m_CF = 1;
13724: } else {
13725: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
13726: }
13727: }
13728:
13729: inline void msdos_int_21h_7303h()
13730: {
13731: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
13732: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
13733: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
13734:
13735: if(GetDiskFreeSpaceA(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
13736: info->size_of_structure = sizeof(ext_space_info_t);
13737: info->structure_version = 0;
13738: info->sectors_per_cluster = sectors_per_cluster;
13739: info->bytes_per_sector = bytes_per_sector;
13740: info->available_clusters_on_drive = free_clusters;
13741: info->total_clusters_on_drive = total_clusters;
13742: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
13743: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
13744: info->available_allocation_units = free_clusters; // ???
13745: info->total_allocation_units = total_clusters; // ???
13746: } else {
13747: REG16(AX) = errno;
13748: m_CF = 1;
13749: }
13750: }
13751:
13752: inline void msdos_int_21h_dbh()
13753: {
13754: // Novell NetWare - Workstation - Get Number of Local Drives
13755: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
13756: REG8(AL) = dos_info->last_drive;
13757: }
13758:
13759: inline void msdos_int_21h_dch()
13760: {
13761: // Novell NetWare - Connection Services - Get Connection Number
13762: REG8(AL) = 0x00;
13763: }
13764:
13765: inline void msdos_int_24h()
13766: {
13767: const char *message = NULL;
13768: int key = 0;
13769:
13770: for(int i = 0; i < array_length(critical_error_table); i++) {
13771: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
13772: if(active_code_page == 932) {
13773: message = critical_error_table[i].message_japanese;
13774: }
13775: if(message == NULL) {
13776: message = critical_error_table[i].message_english;
13777: }
13778: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
13779: strcpy((char *)(mem + WORK_TOP + 1), message);
13780:
13781: SREG(ES) = WORK_TOP >> 4;
13782: i386_load_segment_descriptor(ES);
13783: REG16(DI) = 0x0000;
13784: break;
13785: }
13786: }
13787: fprintf(stderr, "\n%s", message);
13788: if(!(REG8(AH) & 0x80)) {
13789: if(REG8(AH) & 0x01) {
13790: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
13791: } else {
13792: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
13793: }
13794: }
13795: fprintf(stderr, "\n");
13796:
13797: {
13798: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
13799: }
13800: if(REG8(AH) & 0x10) {
13801: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
13802: }
13803: if(REG8(AH) & 0x20) {
13804: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
13805: }
13806: if(REG8(AH) & 0x08) {
13807: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
13808: }
13809: fprintf(stderr, "? ");
13810:
13811: while(1) {
13812: while(!_kbhit()) {
13813: Sleep(10);
13814: }
13815: key = _getch();
13816:
13817: if(key == 'I' || key == 'i') {
13818: if(REG8(AH) & 0x20) {
13819: REG8(AL) = 0;
13820: break;
13821: }
13822: } else if(key == 'R' || key == 'r') {
13823: if(REG8(AH) & 0x10) {
13824: REG8(AL) = 1;
13825: break;
13826: }
13827: } else if(key == 'A' || key == 'a') {
13828: REG8(AL) = 2;
13829: break;
13830: } else if(key == 'F' || key == 'f') {
13831: if(REG8(AH) & 0x08) {
13832: REG8(AL) = 3;
13833: break;
13834: }
13835: }
13836: }
13837: fprintf(stderr, "%c\n", key);
13838: }
13839:
13840: inline void msdos_int_25h()
13841: {
13842: UINT16 seg, ofs;
13843: DWORD dwSize;
13844:
13845: #if defined(HAS_I386)
13846: I386OP(pushf)();
13847: #else
13848: PREFIX86(_pushf());
13849: #endif
13850:
13851: if(!(REG8(AL) < 26)) {
13852: REG8(AL) = 0x01; // unit unknown
13853: m_CF = 1;
13854: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
13855: REG8(AL) = 0x02; // drive not ready
13856: m_CF = 1;
13857: } else {
13858: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
13859: char dev[64];
13860: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
13861:
13862: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
13863: if(hFile == INVALID_HANDLE_VALUE) {
13864: REG8(AL) = 0x02; // drive not ready
13865: m_CF = 1;
13866: } else {
13867: UINT32 top_sector = REG16(DX);
13868: UINT16 sector_num = REG16(CX);
13869: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
13870:
13871: if(sector_num == 0xffff) {
13872: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
13873: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
13874: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
13875: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
13876: buffer_addr = (seg << 4) + ofs;
13877: }
13878: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
13879: // REG8(AL) = 0x02; // drive not ready
13880: // m_CF = 1;
13881: // } else
13882: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
13883: REG8(AL) = 0x08; // sector not found
13884: m_CF = 1;
13885: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
13886: REG8(AL) = 0x0b; // read error
13887: m_CF = 1;
13888: }
13889: CloseHandle(hFile);
13890: }
13891: }
13892: }
13893:
13894: inline void msdos_int_26h()
13895: {
13896: // this operation may cause serious damage for drives, so support only floppy disk...
13897: UINT16 seg, ofs;
13898: DWORD dwSize;
13899:
13900: #if defined(HAS_I386)
13901: I386OP(pushf)();
13902: #else
13903: PREFIX86(_pushf());
13904: #endif
13905:
13906: if(!(REG8(AL) < 26)) {
13907: REG8(AL) = 0x01; // unit unknown
13908: m_CF = 1;
13909: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
13910: REG8(AL) = 0x02; // drive not ready
13911: m_CF = 1;
13912: } else {
13913: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
13914: char dev[64];
13915: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
13916:
13917: if(dpb->media_type == 0xf8) {
13918: // this drive is not a floppy
13919: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
13920: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
13921: // }
13922: REG8(AL) = 0x02; // drive not ready
13923: m_CF = 1;
13924: } else {
13925: HANDLE hFile = CreateFileA(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
13926: if(hFile == INVALID_HANDLE_VALUE) {
13927: REG8(AL) = 0x02; // drive not ready
13928: m_CF = 1;
13929: } else {
13930: UINT32 top_sector = REG16(DX);
13931: UINT16 sector_num = REG16(CX);
13932: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
13933:
13934: if(sector_num == 0xffff) {
13935: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
13936: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
13937: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
13938: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
13939: buffer_addr = (seg << 4) + ofs;
13940: }
13941: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
13942: REG8(AL) = 0x02; // drive not ready
13943: m_CF = 1;
13944: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
13945: REG8(AL) = 0x08; // sector not found
13946: m_CF = 1;
13947: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
13948: REG8(AL) = 0x0a; // write error
13949: m_CF = 1;
13950: }
13951: CloseHandle(hFile);
13952: }
13953: }
13954: }
13955: }
13956:
13957: inline void msdos_int_27h()
13958: {
13959: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
13960: try {
13961: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
13962: } catch(...) {
13963: // recover the broken mcb
13964: int mcb_seg = SREG(CS) - 1;
13965: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
13966:
13967: if(mcb_seg < (MEMORY_END >> 4)) {
13968: mcb->mz = 'M';
13969: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
13970:
13971: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
13972: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
13973: } else {
13974: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
13975: }
13976: } else {
13977: mcb->mz = 'Z';
13978: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
13979: }
13980: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
13981: }
13982: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
13983: }
13984:
13985: inline void msdos_int_29h()
13986: {
13987: msdos_putch_fast(REG8(AL));
13988: }
13989:
13990: inline void msdos_int_2eh()
13991: {
13992: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
13993: memset(tmp, 0, sizeof(tmp));
13994: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
13995: char *token = my_strtok(tmp, " ");
13996: strcpy(command, token);
13997: strcpy(opt, token + strlen(token) + 1);
13998:
13999: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
14000: param->env_seg = 0;
14001: param->cmd_line.w.l = 44;
14002: param->cmd_line.w.h = (WORK_TOP >> 4);
14003: param->fcb1.w.l = 24;
14004: param->fcb1.w.h = (WORK_TOP >> 4);
14005: param->fcb2.w.l = 24;
14006: param->fcb2.w.h = (WORK_TOP >> 4);
14007:
14008: memset(mem + WORK_TOP + 24, 0x20, 20);
14009:
14010: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
14011: cmd_line->len = strlen(opt);
14012: strcpy(cmd_line->cmd, opt);
14013: cmd_line->cmd[cmd_line->len] = 0x0d;
14014:
14015: try {
14016: if(msdos_process_exec(command, param, 0)) {
14017: REG16(AX) = 0xffff; // error before processing command
14018: } else {
14019: // set flag to set retval to ax when the started process is terminated
14020: process_t *process = msdos_process_info_get(current_psp);
14021: process->called_by_int2eh = true;
14022: }
14023: } catch(...) {
14024: REG16(AX) = 0xffff; // error before processing command
14025: }
14026: }
14027:
14028: inline void msdos_int_2fh_05h()
14029: {
14030: switch(REG8(AL)) {
14031: case 0x00:
14032: // critical error handler is installed
14033: REG8(AL) = 0xff;
14034: break;
14035: case 0x01:
14036: case 0x02:
14037: for(int i = 0; i < array_length(standard_error_table); i++) {
14038: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
14039: const char *message = NULL;
14040: if(active_code_page == 932) {
14041: message = standard_error_table[i].message_japanese;
14042: }
14043: if(message == NULL) {
14044: message = standard_error_table[i].message_english;
14045: }
14046: strcpy((char *)(mem + WORK_TOP), message);
14047:
14048: SREG(ES) = WORK_TOP >> 4;
14049: i386_load_segment_descriptor(ES);
14050: REG16(DI) = 0x0000;
14051: REG8(AL) = 0x01;
14052: break;
14053: }
14054: }
14055: break;
14056: default:
14057: 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));
14058: REG16(AX) = 0x01;
14059: m_CF = 1;
14060: }
14061: }
14062:
14063: inline void msdos_int_2fh_06h()
14064: {
14065: switch(REG8(AL)) {
14066: case 0x00:
14067: // ASSIGN is not installed
14068: // REG8(AL) = 0x00;
14069: break;
14070: case 0x01:
14071: // this call is available from within MIRROR.COM even if ASSIGN is not installed
14072: REG16(AX) = 0x01;
14073: m_CF = 1;
14074: break;
14075: default:
14076: 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));
14077: REG16(AX) = 0x01;
14078: m_CF = 1;
14079: break;
14080: }
14081: }
14082:
14083: inline void msdos_int_2fh_11h()
14084: {
14085: switch(REG8(AL)) {
14086: case 0x00:
14087: if(i386_read_stack() == 0xdada) {
14088: #ifdef SUPPORT_MSCDEX
14089: // MSCDEX is installed
14090: REG8(AL) = 0xff;
14091: i386_write_stack(0xadad);
14092: #else
14093: // MSCDEX is not installed
14094: // REG8(AL) = 0x00;
14095: #endif
14096: } else {
14097: // Network Redirector is not installed
14098: // REG8(AL) = 0x00;
14099: }
14100: break;
14101: default:
14102: // 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));
14103: REG16(AX) = 0x49; // network software not installed
14104: m_CF = 1;
14105: break;
14106: }
14107: }
14108:
14109: inline void msdos_int_2fh_12h()
14110: {
14111: switch(REG8(AL)) {
14112: case 0x00:
14113: // DOS 3.0+ internal functions are installed
14114: REG8(AL) = 0xff;
14115: break;
14116: // case 0x01: // DOS 3.0+ internal - Close Current File
14117: case 0x02:
14118: {
14119: UINT16 stack = i386_read_stack();
14120: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
14121: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
14122: i386_load_segment_descriptor(ES);
14123: }
14124: break;
14125: case 0x03:
14126: SREG(DS) = (DEVICE_TOP >> 4);
14127: i386_load_segment_descriptor(DS);
14128: break;
14129: case 0x04:
14130: {
14131: UINT16 stack = i386_read_stack();
14132: REG8(AL) = (stack == '/') ? '\\' : stack;
14133: #if defined(HAS_I386)
14134: m_ZF = (REG8(AL) == '\\');
14135: #else
14136: m_ZeroVal = (REG8(AL) != '\\');
14137: #endif
14138: }
14139: break;
14140: case 0x05:
14141: {
14142: UINT16 c = i386_read_stack();
14143: if((c >> 0) & 0xff) {
14144: msdos_putch((c >> 0) & 0xff);
14145: }
14146: if((c >> 8) & 0xff) {
14147: msdos_putch((c >> 8) & 0xff);
14148: }
14149: }
14150: break;
14151: // case 0x06: // DOS 3.0+ internal - Invoke Critical Error
14152: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
14153: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
14154: // case 0x09: // DOS 3.0+ internal - Flush and Free Disk Buffer
14155: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
14156: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
14157: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
14158: case 0x0d:
14159: {
14160: SYSTEMTIME time;
14161: FILETIME file_time;
14162: WORD dos_date, dos_time;
14163: GetLocalTime(&time);
14164: SystemTimeToFileTime(&time, &file_time);
14165: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
14166: REG16(AX) = dos_date;
14167: REG16(DX) = dos_time;
14168: }
14169: break;
14170: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
14171: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
14172: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
14173: case 0x11:
14174: {
14175: char path[MAX_PATH], *p;
14176: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
14177: my_strupr(path);
14178: while((p = my_strchr(path, '/')) != NULL) {
14179: *p = '\\';
14180: }
14181: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
14182: }
14183: break;
14184: case 0x12:
14185: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
14186: break;
14187: case 0x13:
14188: {
14189: char tmp[2] = {0};
14190: tmp[0] = i386_read_stack();
14191: my_strupr(tmp);
14192: REG8(AL) = tmp[0];
14193: }
14194: break;
14195: case 0x14:
14196: #if defined(HAS_I386)
14197: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
14198: #else
14199: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
14200: #endif
14201: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
14202: break;
14203: // case 0x15: // DOS 3.0+ internal - Flush Buffer
14204: case 0x16:
14205: if(REG16(BX) < 20) {
14206: SREG(ES) = SFT_TOP >> 4;
14207: i386_load_segment_descriptor(ES);
14208: REG16(DI) = 6 + 0x3b * REG16(BX);
14209:
14210: // update system file table
14211: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
14212: if(file_handler[REG16(BX)].valid) {
14213: int count = 0;
14214: for(int i = 0; i < 20; i++) {
14215: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
14216: count++;
14217: }
14218: }
14219: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
14220: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
14221: _lseek(REG16(BX), 0, SEEK_END);
14222: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
14223: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
14224: } else {
14225: memset(sft, 0, 0x3b);
14226: }
14227: } else {
14228: REG16(AX) = 0x06;
14229: m_CF = 1;
14230: }
14231: break;
14232: case 0x17:
14233: {
14234: UINT16 drive = i386_read_stack();
14235: if(msdos_is_valid_drive(drive)) {
14236: msdos_cds_update(drive);
14237: }
14238: REG16(SI) = 88 * drive;
14239: SREG(DS) = (CDS_TOP >> 4);
14240: i386_load_segment_descriptor(DS);
14241: }
14242: break;
14243: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
14244: // case 0x19: // DOS 3.0+ internal - Set Drive???
14245: case 0x1a:
14246: {
14247: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
14248: if(path[1] == ':') {
14249: if(path[0] >= 'a' && path[0] <= 'z') {
14250: REG8(AL) = path[0] - 'a' + 1;
14251: } else if(path[0] >= 'A' && path[0] <= 'Z') {
14252: REG8(AL) = path[0] - 'A' + 1;
14253: } else {
14254: REG8(AL) = 0xff; // invalid
14255: }
14256: strcpy(full, path);
14257: strcpy(path, full + 2);
14258: } else if(GetFullPathNameA(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
14259: if(full[0] >= 'a' && full[0] <= 'z') {
14260: REG8(AL) = full[0] - 'a' + 1;
14261: } else if(full[0] >= 'A' && full[0] <= 'Z') {
14262: REG8(AL) = full[0] - 'A' + 1;
14263: } else {
14264: REG8(AL) = 0xff; // invalid
14265: }
14266: } else {
14267: REG8(AL) = 0x00; // default
14268: }
14269: }
14270: break;
14271: case 0x1b:
14272: {
14273: int year = REG16(CX) + 1980;
14274: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
14275: }
14276: break;
14277: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
14278: // case 0x1d: // DOS 3.0+ internal - Sum Memory
14279: case 0x1e:
14280: {
14281: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
14282: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
14283: if(GetFullPathNameA(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathNameA(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
14284: #if defined(HAS_I386)
14285: m_ZF = (strcmp(full_1st, full_2nd) == 0);
14286: #else
14287: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
14288: #endif
14289: } else {
14290: #if defined(HAS_I386)
14291: m_ZF = (strcmp(path_1st, path_2nd) == 0);
14292: #else
14293: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
14294: #endif
14295: }
14296: }
14297: break;
14298: case 0x1f:
14299: {
14300: UINT16 drive = i386_read_stack();
14301: if(msdos_is_valid_drive(drive)) {
14302: msdos_cds_update(drive);
14303: }
14304: REG16(SI) = 88 * drive;
14305: SREG(ES) = (CDS_TOP >> 4);
14306: i386_load_segment_descriptor(ES);
14307: }
14308: break;
14309: case 0x20:
14310: {
14311: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
14312:
14313: if(fd < 20) {
14314: SREG(ES) = current_psp;
14315: i386_load_segment_descriptor(ES);
14316: REG16(DI) = offsetof(psp_t, file_table) + fd;
14317: } else {
14318: REG16(AX) = 0x06;
14319: m_CF = 1;
14320: }
14321: }
14322: break;
14323: case 0x21:
14324: msdos_int_21h_60h(0);
14325: break;
14326: case 0x22:
14327: {
14328: sda_t *sda = (sda_t *)(mem + SDA_TOP);
14329: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00) != 0xff) {
14330: sda->extended_error_code = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00);
14331: }
14332: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01) != 0xff) {
14333: sda->error_class = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01);
14334: }
14335: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02) != 0xff) {
14336: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02);
14337: }
14338: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03) != 0xff) {
14339: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03);
14340: }
14341: }
14342: break;
14343: // case 0x23: // DOS 3.0+ internal - Check If Character Device
14344: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
14345: case 0x25:
14346: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
14347: break;
14348: case 0x26:
14349: REG8(AL) = REG8(CL);
14350: msdos_int_21h_3dh();
14351: break;
14352: case 0x27:
14353: msdos_int_21h_3eh();
14354: break;
14355: case 0x28:
14356: REG16(AX) = REG16(BP);
14357: msdos_int_21h_42h();
14358: break;
14359: case 0x29:
14360: msdos_int_21h_3fh();
14361: break;
14362: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
14363: case 0x2b:
14364: REG16(AX) = REG16(BP);
14365: msdos_int_21h_44h();
14366: break;
14367: case 0x2c:
14368: REG16(BX) = DEVICE_TOP >> 4;
14369: REG16(AX) = 22;
14370: break;
14371: case 0x2d:
14372: {
14373: sda_t *sda = (sda_t *)(mem + SDA_TOP);
14374: REG16(AX) = sda->extended_error_code;
14375: }
14376: break;
14377: case 0x2e:
14378: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
14379: SREG(ES) = 0x0001;
14380: i386_load_segment_descriptor(ES);
14381: REG16(DI) = 0x00;
14382: } else if(REG8(DL) == 0x08) {
14383: // dummy parameter error message read routine is at fffc:0010
14384: SREG(ES) = DUMMY_TOP >> 4;
14385: i386_load_segment_descriptor(ES);
14386: REG16(DI) = 0x0010;
14387: }
14388: break;
14389: case 0x2f:
14390: if(REG16(DX) != 0) {
14391: dos_major_version = REG8(DL);
14392: dos_minor_version = REG8(DH);
14393: } else {
14394: REG8(DL) = 7;
14395: REG8(DH) = 10;
14396: }
14397: break;
14398: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
14399: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
14400: default:
14401: 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));
14402: REG16(AX) = 0x01;
14403: m_CF = 1;
14404: break;
14405: }
14406: }
14407:
14408: inline void msdos_int_2fh_13h()
14409: {
14410: static UINT16 prevDS = 0, prevDX = 0;
14411: static UINT16 prevES = 0, prevBX = 0;
14412: UINT16 tmp;
14413:
14414: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
14415: i386_load_segment_descriptor(DS);
14416: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
14417:
14418: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
14419: i386_load_segment_descriptor(ES);
14420: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
14421: }
14422:
14423: inline void msdos_int_2fh_14h()
14424: {
14425: switch(REG8(AL)) {
14426: case 0x00:
14427: // NLSFUNC.COM is installed
14428: REG8(AL) = 0xff;
14429: break;
14430: case 0x01:
14431: case 0x03:
14432: REG8(AL) = 0x00;
14433: active_code_page = REG16(BX);
14434: msdos_nls_tables_update();
14435: break;
14436: case 0x02:
14437: REG8(AL) = get_extended_country_info(REG16(BP));
14438: break;
14439: case 0x04:
14440: for(int i = 0;; i++) {
14441: if(country_table[i].code == REG16(DX)) {
14442: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
14443: break;
14444: } else if(country_table[i].code == -1) {
14445: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
14446: break;
14447: }
14448: }
14449: REG8(AL) = 0x00;
14450: break;
14451: default:
14452: 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));
14453: REG16(AX) = 0x01;
14454: m_CF = 1;
14455: break;
14456: }
14457: }
14458:
14459: inline void msdos_int_2fh_15h()
14460: {
14461: switch(REG8(AL)) {
14462: case 0x00: // CD-ROM - Installation Check
14463: if(REG16(BX) == 0x0000) {
14464: #ifdef SUPPORT_MSCDEX
14465: // MSCDEX is installed
14466: REG16(BX) = 0;
14467: for(int i = 0, n = 0; i < 26; i++) {
14468: if(msdos_is_cdrom_drive(i)) {
14469: if(REG16(BX) == 0) {
14470: REG16(CX) = i;
14471: }
14472: REG16(BX)++;
14473: }
14474: }
14475: #else
14476: // MSCDEX is not installed
14477: // REG8(AL) = 0x00;
14478: #endif
14479: } else {
14480: // GRAPHICS.COM is not installed
14481: // REG8(AL) = 0x00;
14482: }
14483: break;
14484: case 0x0b:
14485: // this call is available from within DOSSHELL even if MSCDEX is not installed
14486: REG16(AX) = msdos_is_cdrom_drive(REG8(CL)) ? 0x5ad8 : 0x0000;
14487: REG16(BX) = 0xadad;
14488: break;
14489: case 0x0d:
14490: for(int i = 0, n = 0; i < 26; i++) {
14491: if(msdos_is_cdrom_drive(i)) {
14492: mem[SREG_BASE(ES) + REG16(BX) + (n++)] = i;
14493: }
14494: }
14495: break;
14496: case 0xff:
14497: if(REG16(BX) == 0x0000) {
14498: // CORELCDX is not installed
14499: } else {
14500: 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));
14501: REG16(AX) = 0x01;
14502: m_CF = 1;
14503: }
14504: break;
14505: default:
14506: 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));
14507: REG16(AX) = 0x01;
14508: m_CF = 1;
14509: break;
14510: }
14511: }
14512:
14513: inline void msdos_int_2fh_16h()
14514: {
14515: switch(REG8(AL)) {
14516: case 0x00:
14517: if(no_windows) {
14518: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
14519: // REG8(AL) = 0x00;
14520: } else {
14521: REG8(AL) = win_major_version;
14522: REG8(AH) = win_minor_version;
14523: }
14524: break;
14525: case 0x05: // Windows Enhanced Mode & 286 DOSX Init Broadcast
14526: // from DOSBox
14527: i386_set_a20_line(1);
14528: break;
14529: case 0x06: // Windows Enhanced Mode & 286 DOSX Exit Broadcast
14530: case 0x08: // Windows Enhanced Mode Init Complete Broadcast
14531: case 0x09: // Windows Enhanced Mode Begin Exit Broadcast
14532: break;
14533: case 0x07:
14534: // Virtual Device Call API
14535: break;
14536: case 0x0a:
14537: if(!no_windows) {
14538: REG16(AX) = 0x0000;
14539: REG8(BH) = win_major_version;
14540: REG8(BL) = win_minor_version;
14541: // REG16(CX) = 0x0002; // standard
14542: REG16(CX) = 0x0003; // enhanced
14543: }
14544: break;
14545: case 0x0b:
14546: // no TRS, keep ES:DI = 0000h:0000h
14547: case 0x0e:
14548: case 0x0f:
14549: case 0x10:
14550: case 0x11:
14551: case 0x12:
14552: case 0x13:
14553: case 0x14:
14554: case 0x15:
14555: case 0x81:
14556: case 0x82:
14557: case 0x84:
14558: case 0x85:
14559: case 0x86:
14560: case 0x87:
14561: case 0x89:
14562: case 0x8a:
14563: // function not supported, do not clear AX
14564: break;
14565: case 0x80:
14566: Sleep(10);
14567: REQUEST_HARDWRE_UPDATE();
14568: REG8(AL) = 0x00;
14569: break;
14570: case 0x83:
14571: REG16(BX) = 0x01; // system vm id
14572: break;
14573: case 0x8e:
14574: REG16(AX) = 0x00; // failed
14575: break;
14576: case 0x8f:
14577: switch(REG8(DH)) {
14578: case 0x01:
14579: // REG16(AX) = 0x0000; // close command selected but not yet acknowledged
14580: // REG16(AX) = 0x0001; // close command issued and acknowledged
14581: REG16(AX) = 0x168f; // close command not selected -- application should continue
14582: break;
14583: default:
14584: REG16(AX) = 0x0000; // successful
14585: break;
14586: }
14587: break;
14588: default:
14589: 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));
14590: REG16(AX) = 0x01;
14591: m_CF = 1;
14592: break;
14593: }
14594: }
14595:
14596: inline void msdos_int_2fh_19h()
14597: {
14598: switch(REG8(AL)) {
14599: case 0x00:
14600: // SHELLB.COM is not installed
14601: // REG8(AL) = 0x00;
14602: break;
14603: case 0x01:
14604: case 0x02:
14605: case 0x03:
14606: case 0x04:
14607: REG16(AX) = 0x01;
14608: m_CF = 1;
14609: break;
14610: case 0x80:
14611: // IBM ROM-DOS v4.0 is not installed
14612: // REG8(AL) = 0x00;
14613: break;
14614: default:
14615: 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));
14616: REG16(AX) = 0x01;
14617: m_CF = 1;
14618: break;
14619: }
14620: }
14621:
14622: inline void msdos_int_2fh_1ah()
14623: {
14624: switch(REG8(AL)) {
14625: case 0x00:
14626: // ANSI.SYS is installed
14627: REG8(AL) = 0xff;
14628: break;
14629: case 0x01:
14630: if(REG8(CL) == 0x5f) {
14631: // set display information
14632: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) >= 14) {
14633: int cur_width = *(UINT16 *)(mem + 0x44a) + 0;
14634: int cur_height = *(UINT8 *)(mem + 0x484) + 1;
14635: int new_width = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // character columns
14636: int new_height = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10); // character rows
14637:
14638: if(cur_width != new_width || cur_height != new_height) {
14639: pcbios_set_console_size(new_width, new_height, true);
14640: }
14641: }
14642: } else if(REG8(CL) == 0x7f) {
14643: // get display information
14644: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0; // level (0 for DOS 4.x-6.0)
14645: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0; // reserved (0)
14646: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14; // length of following data (14)
14647: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1; // bit 0 set for blink, clear for intensity
14648: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1; // mode type (1=text, 2=graphics)
14649: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0; // reserved (0)
14650: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4; // 4 bits per pixel
14651: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a) + 0); // pixel columns
14652: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1); // pixel rows
14653: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a) + 0; // character columns
14654: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1; // character rows
14655: } else {
14656: 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));
14657: REG16(AX) = 0x01;
14658: m_CF = 1;
14659: }
14660: break;
14661: default:
14662: 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));
14663: REG16(AX) = 0x01;
14664: m_CF = 1;
14665: break;
14666: }
14667: }
14668:
14669: inline void msdos_int_2fh_40h()
14670: {
14671: switch(REG8(AL)) {
14672: case 0x00:
14673: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
14674: REG8(AL) = 0x01; // does not virtualize video access
14675: break;
14676: case 0x10:
14677: // OS/2 v2.0+ - Installation Check
14678: REG16(AX) = 0x01;
14679: m_CF = 1;
14680: break;
14681: default:
14682: 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));
14683: REG16(AX) = 0x01;
14684: m_CF = 1;
14685: break;
14686: }
14687: }
14688:
14689: inline void msdos_int_2fh_43h()
14690: {
14691: switch(REG8(AL)) {
14692: case 0x00:
14693: // XMS is installed ?
14694: #ifdef SUPPORT_XMS
14695: if(support_xms) {
14696: REG8(AL) = 0x80;
14697: }
14698: #endif
14699: break;
14700: case 0x08:
14701: #ifdef SUPPORT_XMS
14702: if(support_xms) {
14703: REG8(AL) = 0x43;
14704: REG8(BL) = 0x01; // IBM PC/AT
14705: REG8(BH) = 0x01; // Fast AT A20 switch time
14706: }
14707: #endif
14708: break;
14709: case 0x10:
14710: SREG(ES) = XMS_TOP >> 4;
14711: i386_load_segment_descriptor(ES);
14712: REG16(BX) = 0x15;
14713: break;
14714: case 0xe0:
14715: // DOS Protected Mode Services (DPMS) v1.0 is not installed
14716: if(REG16(BX) == 0x0000 && REG16(CX) == 0x4450 && REG16(DX) == 0x4d53) {
14717: break;
14718: }
14719: default:
14720: 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));
14721: REG16(AX) = 0x01;
14722: m_CF = 1;
14723: break;
14724: }
14725: }
14726:
14727: inline void msdos_int_2fh_46h()
14728: {
14729: switch(REG8(AL)) {
14730: case 0x80:
14731: // Windows v3.0 is not installed
14732: // REG8(AL) = 0x00;
14733: break;
14734: default:
14735: 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));
14736: REG16(AX) = 0x01;
14737: m_CF = 1;
14738: break;
14739: }
14740: }
14741:
14742: inline void msdos_int_2fh_48h()
14743: {
14744: switch(REG8(AL)) {
14745: case 0x00:
14746: // DOSKEY is not installed
14747: // REG8(AL) = 0x00;
14748: break;
14749: case 0x10:
14750: msdos_int_21h_0ah();
14751: REG16(AX) = 0x00;
14752: break;
14753: default:
14754: 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));
14755: REG16(AX) = 0x01;
14756: m_CF = 1;
14757: break;
14758: }
14759: }
14760:
14761: inline void msdos_int_2fh_4ah()
14762: {
14763: switch(REG8(AL)) {
14764: #ifdef SUPPORT_HMA
14765: case 0x01: // DOS 5.0+ - Query Free HMA Space
14766: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
14767: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14768: // restore first free mcb in high memory area
14769: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14770: }
14771: int offset = 0xffff;
14772: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
14773: REG16(DI) = offset + 0x10;
14774: } else {
14775: REG16(DI) = 0xffff;
14776: }
14777: } else {
14778: // HMA is already used
14779: REG16(BX) = 0;
14780: REG16(DI) = 0xffff;
14781: }
14782: SREG(ES) = 0xffff;
14783: i386_load_segment_descriptor(ES);
14784: break;
14785: case 0x02: // DOS 5.0+ - Allocate HMA Space
14786: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
14787: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14788: // restore first free mcb in high memory area
14789: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14790: }
14791: int size = REG16(BX), offset;
14792: if((size % 16) != 0) {
14793: size &= ~15;
14794: size += 16;
14795: }
14796: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
14797: REG16(BX) = size;
14798: REG16(DI) = offset + 0x10;
14799: is_hma_used_by_int_2fh = true;
14800: } else {
14801: REG16(BX) = 0;
14802: REG16(DI) = 0xffff;
14803: }
14804: } else {
14805: // HMA is already used
14806: REG16(BX) = 0;
14807: REG16(DI) = 0xffff;
14808: }
14809: SREG(ES) = 0xffff;
14810: i386_load_segment_descriptor(ES);
14811: break;
14812: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
14813: if(REG8(DL) == 0x00) {
14814: if(!is_hma_used_by_xms) {
14815: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14816: // restore first free mcb in high memory area
14817: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14818: is_hma_used_by_int_2fh = false;
14819: }
14820: int size = REG16(BX), offset;
14821: if((size % 16) != 0) {
14822: size &= ~15;
14823: size += 16;
14824: }
14825: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
14826: // REG16(BX) = size;
14827: SREG(ES) = 0xffff;
14828: i386_load_segment_descriptor(ES);
14829: REG16(DI) = offset + 0x10;
14830: is_hma_used_by_int_2fh = true;
14831: } else {
14832: REG16(DI) = 0xffff;
14833: }
14834: } else {
14835: REG16(DI) = 0xffff;
14836: }
14837: } else if(REG8(DL) == 0x01) {
14838: if(!is_hma_used_by_xms) {
14839: int size = REG16(BX);
14840: if((size % 16) != 0) {
14841: size &= ~15;
14842: size += 16;
14843: }
14844: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
14845: // memory block address is not changed
14846: } else {
14847: REG16(DI) = 0xffff;
14848: }
14849: } else {
14850: REG16(DI) = 0xffff;
14851: }
14852: } else if(REG8(DL) == 0x02) {
14853: if(!is_hma_used_by_xms) {
14854: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14855: // restore first free mcb in high memory area
14856: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14857: is_hma_used_by_int_2fh = false;
14858: } else {
14859: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
14860: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
14861: is_hma_used_by_int_2fh = false;
14862: }
14863: }
14864: }
14865: } else {
14866: 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));
14867: REG16(AX) = 0x01;
14868: m_CF = 1;
14869: }
14870: break;
14871: case 0x04: // Windows95 - Get Start of HMA Memory Chain
14872: if(!is_hma_used_by_xms) {
14873: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14874: // restore first free mcb in high memory area
14875: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14876: is_hma_used_by_int_2fh = false;
14877: }
14878: REG16(AX) = 0x0000;
14879: SREG(ES) = 0xffff;
14880: i386_load_segment_descriptor(ES);
14881: REG16(DI) = 0x10;
14882: }
14883: break;
14884: #else
14885: case 0x01:
14886: case 0x02:
14887: // HMA is already used
14888: REG16(BX) = 0x0000;
14889: SREG(ES) = 0xffff;
14890: i386_load_segment_descriptor(ES);
14891: REG16(DI) = 0xffff;
14892: break;
14893: case 0x03:
14894: // unable to allocate
14895: REG16(DI) = 0xffff;
14896: break;
14897: case 0x04:
14898: // function not supported, do not clear AX
14899: break;
14900: #endif
14901: case 0x10:
14902: switch(REG16(BX)) {
14903: case 0x0000:
14904: case 0x0001:
14905: case 0x0002:
14906: case 0x0003:
14907: case 0x0004:
14908: case 0x0005:
14909: case 0x0006:
14910: case 0x0007:
14911: case 0x0008:
14912: case 0x000a:
14913: case 0x1234:
14914: // SMARTDRV v4.00+ is not installed
14915: break;
14916: default:
14917: 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));
14918: REG16(AX) = 0x01;
14919: m_CF = 1;
14920: break;
14921: }
14922: break;
14923: case 0x11:
14924: switch(REG16(BX)) {
14925: case 0x0000:
14926: case 0x0001:
14927: case 0x0002:
14928: case 0x0003:
14929: case 0x0004:
14930: case 0x0005:
14931: case 0x0006:
14932: case 0x0007:
14933: case 0x0008:
14934: case 0x0009:
14935: case 0x000a:
14936: case 0x000b:
14937: case 0xfffe:
14938: case 0xffff:
14939: // DBLSPACE.BIN is not installed
14940: break;
14941: default:
14942: 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));
14943: REG16(AX) = 0x01;
14944: m_CF = 1;
14945: break;
14946: }
14947: break;
14948: case 0x12:
14949: if(REG16(CX) == 0x4d52 && REG16(DX) == 0x4349) {
14950: // Microsoft Realtime Compression Interface (MRCI) is not installed
14951: } else if(REG16(CX) == 0x5354 && REG16(DX) == 0x4143) {
14952: // Stacker 4 LZS Compression Interface (LZSAPI) is not installed
14953: } else {
14954: 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));
14955: REG16(AX) = 0x01;
14956: m_CF = 1;
14957: }
14958: break;
14959: case 0x13:
14960: // DBLSPACE.BIN is not installed
14961: break;
14962: default:
14963: 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));
14964: REG16(AX) = 0x01;
14965: m_CF = 1;
14966: break;
14967: }
14968: }
14969:
14970: inline void msdos_int_2fh_4bh()
14971: {
14972: switch(REG8(AL)) {
14973: case 0x01:
14974: case 0x02:
14975: // Task Switcher is not installed
14976: break;
14977: case 0x03:
14978: // this call is available from within DOSSHELL even if the task switcher is not installed
14979: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
14980: break;
14981: case 0x04:
14982: REG16(BX) = 0x0000; // free switcher id successfully
14983: break;
14984: case 0x05:
14985: REG16(BX) = 0x0000; // no instance data chain
14986: SREG(ES) = 0x0000;
14987: i386_load_segment_descriptor(ES);
14988: break;
14989: default:
14990: 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));
14991: REG16(AX) = 0x01;
14992: m_CF = 1;
14993: break;
14994: }
14995: }
14996:
14997: inline void msdos_int_2fh_4dh()
14998: {
14999: switch(REG8(AL)) {
15000: case 0x00:
15001: // KKCFUNC is not installed ???
15002: break;
15003: default:
15004: // 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));
15005: REG16(AX) = 0x01; // invalid function
15006: m_CF = 1;
15007: break;
15008: }
15009: }
15010:
15011: inline void msdos_int_2fh_4fh()
15012: {
15013: switch(REG8(AL)) {
15014: case 0x00:
15015: // BILING is installed
15016: REG16(AX) = 0x0000;
15017: REG8(DL) = 0x01; // major version
15018: REG8(DH) = 0x00; // minor version
15019: break;
15020: case 0x01:
15021: REG16(AX) = 0x0000;
15022: REG16(BX) = active_code_page;
15023: break;
15024: default:
15025: 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));
15026: REG16(AX) = 0x01;
15027: m_CF = 1;
15028: break;
15029: }
15030: }
15031:
15032: inline void msdos_int_2fh_55h()
15033: {
15034: switch(REG8(AL)) {
15035: case 0x00:
15036: case 0x01:
15037: // 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));
15038: break;
15039: default:
15040: 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));
15041: REG16(AX) = 0x01;
15042: m_CF = 1;
15043: break;
15044: }
15045: }
15046:
15047: inline void msdos_int_2fh_56h()
15048: {
15049: switch(REG8(AL)) {
15050: case 0x00:
15051: // INTERLNK is not installed
15052: break;
15053: case 0x01:
15054: // this call is available from within SCANDISK even if INTERLNK is not installed
15055: // if(msdos_is_remote_drive(REG8(BH))) {
15056: // REG8(AL) = 0x00;
15057: // }
15058: break;
15059: default:
15060: 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));
15061: REG16(AX) = 0x01;
15062: m_CF = 1;
15063: break;
15064: }
15065: }
15066:
15067: inline void msdos_int_2fh_adh()
15068: {
15069: switch(REG8(AL)) {
15070: case 0x00:
15071: // DISPLAY.SYS is installed
15072: REG8(AL) = 0xff;
15073: REG16(BX) = 0x100; // ???
15074: break;
15075: case 0x01:
15076: active_code_page = REG16(BX);
15077: msdos_nls_tables_update();
15078: REG16(AX) = 0x01;
15079: break;
15080: case 0x02:
15081: REG16(BX) = active_code_page;
15082: break;
15083: case 0x03:
15084: // FIXME
15085: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
15086: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
15087: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
15088: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
15089: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
15090: break;
15091: case 0x80:
15092: // KEYB.COM is not installed
15093: break;
15094: default:
15095: 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));
15096: REG16(AX) = 0x01;
15097: m_CF = 1;
15098: break;
15099: }
15100: }
15101:
15102: inline void msdos_int_2fh_aeh()
15103: {
15104: switch(REG8(AL)) {
15105: case 0x00:
15106: // FIXME: we need to check the given command line
15107: REG8(AL) = 0x00; // the command should be executed as usual
15108: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
15109: break;
15110: case 0x01:
15111: {
15112: char command[MAX_PATH];
15113: memset(command, 0, sizeof(command));
15114: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
15115:
15116: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
15117: param->env_seg = 0;
15118: param->cmd_line.w.l = 44;
15119: param->cmd_line.w.h = (WORK_TOP >> 4);
15120: param->fcb1.w.l = 24;
15121: param->fcb1.w.h = (WORK_TOP >> 4);
15122: param->fcb2.w.l = 24;
15123: param->fcb2.w.h = (WORK_TOP >> 4);
15124:
15125: memset(mem + WORK_TOP + 24, 0x20, 20);
15126:
15127: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
15128: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
15129: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
15130: cmd_line->cmd[cmd_line->len] = 0x0d;
15131:
15132: try {
15133: msdos_process_exec(command, param, 0);
15134: } catch(...) {
15135: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
15136: }
15137: }
15138: break;
15139: default:
15140: 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));
15141: REG16(AX) = 0x01;
15142: m_CF = 1;
15143: break;
15144: }
15145: }
15146:
15147: inline void msdos_int_2fh_b7h()
15148: {
15149: switch(REG8(AL)) {
15150: case 0x00:
15151: // APPEND is not installed
15152: // REG8(AL) = 0x00;
15153: break;
15154: case 0x06:
15155: REG16(BX) = 0x0000;
15156: break;
15157: case 0x07:
15158: case 0x11:
15159: // COMMAND.COM calls this service without checking APPEND is installed
15160: break;
15161: default:
15162: 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));
15163: REG16(AX) = 0x01;
15164: m_CF = 1;
15165: break;
15166: }
15167: }
15168:
15169: inline void msdos_int_33h_0000h()
15170: {
15171: REG16(AX) = 0xffff; // hardware/driver installed
15172: REG16(BX) = MAX_MOUSE_BUTTONS;
15173: }
15174:
15175: inline void msdos_int_33h_0001h()
15176: {
15177: if(mouse.hidden > 0) {
15178: mouse.hidden--;
15179: }
15180: if(mouse.hidden == 0) {
15181: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), (dwConsoleMode | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS) & ~ENABLE_QUICK_EDIT_MODE);
15182: pic[1].imr &= ~0x10; // enable irq12
15183: }
15184: }
15185:
15186: inline void msdos_int_33h_0002h()
15187: {
15188: mouse.hidden++;
15189: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) {
15190: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS);
15191: } else {
15192: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
15193: }
15194: pic[1].imr |= 0x10; // disable irq12
15195: }
15196:
15197: inline void msdos_int_33h_0003h()
15198: {
15199: // if(mouse.hidden > 0) {
15200: update_console_input();
15201: // }
15202: REG16(BX) = mouse.get_buttons();
15203: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
15204: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
15205: }
15206:
15207: inline void msdos_int_33h_0004h()
15208: {
15209: mouse.position.x = REG16(CX);
15210: mouse.position.x = REG16(DX);
15211: }
15212:
15213: inline void msdos_int_33h_0005h()
15214: {
15215: // if(mouse.hidden > 0) {
15216: update_console_input();
15217: // }
15218: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
15219: int idx = REG16(BX);
15220: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff);
15221: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x));
15222: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.buttons[idx].pressed_position.y));
15223: mouse.buttons[idx].pressed_times = 0;
15224: } else {
15225: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
15226: }
15227: REG16(AX) = mouse.get_buttons();
15228: }
15229:
15230: inline void msdos_int_33h_0006h()
15231: {
15232: // if(mouse.hidden > 0) {
15233: update_console_input();
15234: // }
15235: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
15236: int idx = REG16(BX);
15237: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff);
15238: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x));
15239: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.buttons[idx].released_position.y));
15240: mouse.buttons[idx].released_times = 0;
15241: } else {
15242: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
15243: }
15244: REG16(AX) = mouse.get_buttons();
15245: }
15246:
15247: inline void msdos_int_33h_0007h()
15248: {
15249: mouse.min_position.x = min(REG16(CX), REG16(DX));
15250: mouse.max_position.x = max(REG16(CX), REG16(DX));
15251: }
15252:
15253: inline void msdos_int_33h_0008h()
15254: {
15255: mouse.min_position.y = min(REG16(CX), REG16(DX));
15256: mouse.max_position.y = max(REG16(CX), REG16(DX));
15257: }
15258:
15259: inline void msdos_int_33h_0009h()
15260: {
15261: mouse.hot_spot[0] = REG16(BX);
15262: mouse.hot_spot[1] = REG16(CX);
15263: }
15264:
15265: inline void msdos_int_33h_000ah()
15266: {
15267: mouse.screen_mask = REG16(CX);
15268: mouse.cursor_mask = REG16(DX);
15269: }
15270:
15271: inline void msdos_int_33h_000bh()
15272: {
15273: // if(mouse.hidden > 0) {
15274: update_console_input();
15275: // }
15276: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
15277: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
15278: mouse.prev_position.x = mouse.position.x;
15279: mouse.prev_position.y = mouse.position.y;
15280: REG16(CX) = dx;
15281: REG16(DX) = dy;
15282: }
15283:
15284: inline void msdos_int_33h_000ch()
15285: {
15286: mouse.call_mask = REG16(CX);
15287: mouse.call_addr.w.l = REG16(DX);
15288: mouse.call_addr.w.h = SREG(ES);
15289: }
15290:
15291: inline void msdos_int_33h_000fh()
15292: {
15293: mouse.mickey.x = REG16(CX);
15294: mouse.mickey.y = REG16(DX);
15295: }
15296:
15297: inline void msdos_int_33h_0011h()
15298: {
15299: REG16(AX) = 0xffff;
15300: REG16(BX) = MAX_MOUSE_BUTTONS;
15301: }
15302:
15303: inline void msdos_int_33h_0014h()
15304: {
15305: UINT16 old_mask = mouse.call_mask;
15306: UINT16 old_ofs = mouse.call_addr.w.l;
15307: UINT16 old_seg = mouse.call_addr.w.h;
15308:
15309: mouse.call_mask = REG16(CX);
15310: mouse.call_addr.w.l = REG16(DX);
15311: mouse.call_addr.w.h = SREG(ES);
15312:
15313: REG16(CX) = old_mask;
15314: REG16(DX) = old_ofs;
15315: SREG(ES) = old_seg;
15316: i386_load_segment_descriptor(ES);
15317: }
15318:
15319: inline void msdos_int_33h_0015h()
15320: {
15321: REG16(BX) = sizeof(mouse);
15322: }
15323:
15324: inline void msdos_int_33h_0016h()
15325: {
15326: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
15327: }
15328:
15329: inline void msdos_int_33h_0017h()
15330: {
15331: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
15332: }
15333:
15334: inline void msdos_int_33h_0018h()
15335: {
15336: for(int i = 0; i < 8; i++) {
15337: if(REG16(CX) & (1 << i)) {
15338: if(mouse.call_addr_alt[i].dw && !(REG16(DX) == 0 && SREG(ES) == 0)) {
15339: // event handler already exists
15340: REG16(AX) = 0xffff;
15341: break;
15342: }
15343: mouse.call_addr_alt[i].w.l = REG16(DX);
15344: mouse.call_addr_alt[i].w.h = SREG(ES);
15345: }
15346: }
15347: }
15348:
15349: inline void msdos_int_33h_0019h()
15350: {
15351: UINT16 call_mask = REG16(CX);
15352:
15353: REG16(CX) = 0;
15354:
15355: for(int i = 0; i < 8; i++) {
15356: if((call_mask & (1 << i)) && mouse.call_addr_alt[i].dw) {
15357: for(int j = 0; j < 8; j++) {
15358: if((call_mask & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
15359: REG16(CX) |= (1 << j);
15360: }
15361: }
15362: REG16(DX) = mouse.call_addr_alt[i].w.l;
15363: REG16(BX) = mouse.call_addr_alt[i].w.h;
15364: break;
15365: }
15366: }
15367: }
15368:
15369: inline void msdos_int_33h_001ah()
15370: {
15371: mouse.sensitivity[0] = REG16(BX);
15372: mouse.sensitivity[1] = REG16(CX);
15373: mouse.sensitivity[2] = REG16(DX);
15374: }
15375:
15376: inline void msdos_int_33h_001bh()
15377: {
15378: REG16(BX) = mouse.sensitivity[0];
15379: REG16(CX) = mouse.sensitivity[1];
15380: REG16(DX) = mouse.sensitivity[2];
15381: }
15382:
15383: inline void msdos_int_33h_001dh()
15384: {
15385: mouse.display_page = REG16(BX);
15386: }
15387:
15388: inline void msdos_int_33h_001eh()
15389: {
15390: REG16(BX) = mouse.display_page;
15391: }
15392:
15393: inline void msdos_int_33h_001fh()
15394: {
15395: // from DOSBox
15396: REG16(BX) = 0x0000;
15397: SREG(ES) = 0x0000;
15398: i386_load_segment_descriptor(ES);
15399: mouse.enabled = false;
15400: mouse.old_hidden = mouse.hidden;
15401: mouse.hidden = 1;
15402: }
15403:
15404: inline void msdos_int_33h_0020h()
15405: {
15406: // from DOSBox
15407: mouse.enabled = true;
15408: mouse.hidden = mouse.old_hidden;
15409: }
15410:
15411: inline void msdos_int_33h_0021h()
15412: {
15413: REG16(AX) = 0xffff;
15414: REG16(BX) = MAX_MOUSE_BUTTONS;
15415: }
15416:
15417: inline void msdos_int_33h_0022h()
15418: {
15419: mouse.language = REG16(BX);
15420: }
15421:
15422: inline void msdos_int_33h_0023h()
15423: {
15424: REG16(BX) = mouse.language;
15425: }
15426:
15427: inline void msdos_int_33h_0024h()
15428: {
15429: REG16(BX) = 0x0805; // V8.05
15430: REG16(CX) = 0x0400; // PS/2
15431: }
15432:
15433: inline void msdos_int_33h_0025h()
15434: {
15435: REG16(AX) = 0x8000; // driver (not TSR), software text cursor
15436: }
15437:
15438: inline void msdos_int_33h_0026h()
15439: {
15440: REG16(BX) = 0x0000;
15441: REG16(CX) = mouse.max_position.x;
15442: REG16(DX) = mouse.max_position.y;
15443: }
15444:
15445: inline void msdos_int_33h_0027h()
15446: {
15447: // if(mouse.hidden > 0) {
15448: update_console_input();
15449: // }
15450: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
15451: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
15452: mouse.prev_position.x = mouse.position.x;
15453: mouse.prev_position.y = mouse.position.y;
15454: REG16(AX) = mouse.screen_mask;
15455: REG16(BX) = mouse.cursor_mask;
15456: REG16(CX) = dx;
15457: REG16(DX) = dy;
15458: }
15459:
15460: inline void msdos_int_33h_0028h()
15461: {
15462: if(REG16(CX) != 0) {
15463: UINT8 tmp = REG8(AL);
15464: REG8(AL) = REG8(CL);
15465: pcbios_int_10h_00h();
15466: REG8(AL) = tmp;
15467: }
15468: REG8(CL) = 0x00; // successful
15469: }
15470:
15471: inline void msdos_int_33h_0029h()
15472: {
15473: switch(REG16(CX)) {
15474: case 0x0000:
15475: REG16(CX) = 0x0003;
15476: sprintf((char *)(mem + WORK_TOP), "TEXT Mode (80x25)$");
15477: break;
15478: case 0x0003:
15479: REG16(CX) = 0x0070;
15480: sprintf((char *)(mem + WORK_TOP), "V-TEXT Mode (%dx%d)$", scr_width, scr_height);
15481: break;
15482: case 0x0070:
15483: REG16(CX) = 0x0071;
15484: sprintf((char *)(mem + WORK_TOP), "Extended CGA V-TEXT Mode (%dx%d)$", scr_width, scr_height);
15485: break;
15486: case 0x0071:
15487: REG16(CX) = 0x0073;
15488: sprintf((char *)(mem + WORK_TOP), "Extended CGA TEXT Mode (80x25)$");
15489: break;
15490: default:
15491: REG16(CX) = 0x0000;
15492: break;
15493: }
15494: if(REG16(CX) != 0) {
15495: SREG(DS) = (WORK_TOP >> 4);
15496: } else {
15497: SREG(DS) = 0x0000;
15498: }
15499: i386_load_segment_descriptor(DS);
15500: REG16(DX) = 0x0000;
15501: }
15502:
15503: inline void msdos_int_33h_002ah()
15504: {
15505: REG16(AX) = -mouse.hidden;
15506: REG16(BX) = mouse.hot_spot[0];
15507: REG16(CX) = mouse.hot_spot[1];
15508: REG16(DX) = 4; // PS/2
15509: }
15510:
15511: inline void msdos_int_33h_0031h()
15512: {
15513: REG16(AX) = mouse.min_position.x;
15514: REG16(BX) = mouse.min_position.y;
15515: REG16(CX) = mouse.max_position.x;
15516: REG16(DX) = mouse.max_position.y;
15517: }
15518:
15519: inline void msdos_int_33h_0032h()
15520: {
15521: REG16(AX) = 0;
15522: REG16(AX) |= 0x8000; // 0025h
15523: REG16(AX) |= 0x4000; // 0026h
15524: REG16(AX) |= 0x2000; // 0027h
15525: // REG16(AX) |= 0x1000; // 0028h
15526: // REG16(AX) |= 0x0800; // 0029h
15527: REG16(AX) |= 0x0400; // 002ah
15528: // REG16(AX) |= 0x0200; // 002bh
15529: // REG16(AX) |= 0x0100; // 002ch
15530: // REG16(AX) |= 0x0080; // 002dh
15531: // REG16(AX) |= 0x0040; // 002eh
15532: REG16(AX) |= 0x0020; // 002fh
15533: // REG16(AX) |= 0x0010; // 0030h
15534: REG16(AX) |= 0x0008; // 0031h
15535: REG16(AX) |= 0x0004; // 0032h
15536: // REG16(AX) |= 0x0002; // 0033h
15537: // REG16(AX) |= 0x0001; // 0034h
15538: }
15539:
15540: inline void msdos_int_33h_004dh()
15541: {
15542: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), "Copyright 2017 MS-DOS Player");
15543: }
15544:
15545: inline void msdos_int_33h_006dh()
15546: {
15547: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x08; // V8.05
15548: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = 0x05;
15549: }
15550:
15551: inline void msdos_int_67h_40h()
15552: {
15553: if(!support_ems) {
15554: REG8(AH) = 0x84;
15555: } else {
15556: REG8(AH) = 0x00;
15557: }
15558: }
15559:
15560: inline void msdos_int_67h_41h()
15561: {
15562: if(!support_ems) {
15563: REG8(AH) = 0x84;
15564: } else {
15565: REG8(AH) = 0x00;
15566: REG16(BX) = EMS_TOP >> 4;
15567: }
15568: }
15569:
15570: inline void msdos_int_67h_42h()
15571: {
15572: if(!support_ems) {
15573: REG8(AH) = 0x84;
15574: } else {
15575: REG8(AH) = 0x00;
15576: REG16(BX) = free_ems_pages;
15577: REG16(DX) = MAX_EMS_PAGES;
15578: }
15579: }
15580:
15581: inline void msdos_int_67h_43h()
15582: {
15583: if(!support_ems) {
15584: REG8(AH) = 0x84;
15585: } else if(REG16(BX) > MAX_EMS_PAGES) {
15586: REG8(AH) = 0x87;
15587: } else if(REG16(BX) > free_ems_pages) {
15588: REG8(AH) = 0x88;
15589: } else if(REG16(BX) == 0) {
15590: REG8(AH) = 0x89;
15591: } else {
15592: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
15593: if(!ems_handles[i].allocated) {
15594: ems_allocate_pages(i, REG16(BX));
15595: REG8(AH) = 0x00;
15596: REG16(DX) = i;
15597: return;
15598: }
15599: }
15600: REG8(AH) = 0x85;
15601: }
15602: }
15603:
15604: inline void msdos_int_67h_44h()
15605: {
15606: if(!support_ems) {
15607: REG8(AH) = 0x84;
15608: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15609: REG8(AH) = 0x83;
15610: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
15611: REG8(AH) = 0x8a;
15612: // } else if(!(REG8(AL) < 4)) {
15613: // REG8(AH) = 0x8b;
15614: } else if(REG16(BX) == 0xffff) {
15615: ems_unmap_page(REG8(AL) & 3);
15616: REG8(AH) = 0x00;
15617: } else {
15618: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
15619: REG8(AH) = 0x00;
15620: }
15621: }
15622:
15623: inline void msdos_int_67h_45h()
15624: {
15625: if(!support_ems) {
15626: REG8(AH) = 0x84;
15627: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15628: REG8(AH) = 0x83;
15629: } else {
15630: ems_release_pages(REG16(DX));
15631: REG8(AH) = 0x00;
15632: }
15633: }
15634:
15635: inline void msdos_int_67h_46h()
15636: {
15637: if(!support_ems) {
15638: REG8(AH) = 0x84;
15639: } else {
15640: // REG16(AX) = 0x0032; // EMS 3.2
15641: REG16(AX) = 0x0040; // EMS 4.0
15642: }
15643: }
15644:
15645: inline void msdos_int_67h_47h()
15646: {
15647: // NOTE: the map data should be stored in the specified ems page, not process data
15648: process_t *process = msdos_process_info_get(current_psp);
15649:
15650: if(!support_ems) {
15651: REG8(AH) = 0x84;
15652: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15653: // REG8(AH) = 0x83;
15654: } else if(process->ems_pages_stored) {
15655: REG8(AH) = 0x8d;
15656: } else {
15657: for(int i = 0; i < 4; i++) {
15658: process->ems_pages[i].handle = ems_pages[i].handle;
15659: process->ems_pages[i].page = ems_pages[i].page;
15660: process->ems_pages[i].mapped = ems_pages[i].mapped;
15661: }
15662: process->ems_pages_stored = true;
15663: REG8(AH) = 0x00;
15664: }
15665: }
15666:
15667: inline void msdos_int_67h_48h()
15668: {
15669: // NOTE: the map data should be restored from the specified ems page, not process data
15670: process_t *process = msdos_process_info_get(current_psp);
15671:
15672: if(!support_ems) {
15673: REG8(AH) = 0x84;
15674: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15675: // REG8(AH) = 0x83;
15676: } else if(!process->ems_pages_stored) {
15677: REG8(AH) = 0x8e;
15678: } else {
15679: for(int i = 0; i < 4; i++) {
15680: if(process->ems_pages[i].mapped) {
15681: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
15682: } else {
15683: ems_unmap_page(i);
15684: }
15685: }
15686: process->ems_pages_stored = false;
15687: REG8(AH) = 0x00;
15688: }
15689: }
15690:
15691: inline void msdos_int_67h_4bh()
15692: {
15693: if(!support_ems) {
15694: REG8(AH) = 0x84;
15695: } else {
15696: REG8(AH) = 0x00;
15697: REG16(BX) = 0;
15698: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
15699: if(ems_handles[i].allocated) {
15700: REG16(BX)++;
15701: }
15702: }
15703: }
15704: }
15705:
15706: inline void msdos_int_67h_4ch()
15707: {
15708: if(!support_ems) {
15709: REG8(AH) = 0x84;
15710: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15711: REG8(AH) = 0x83;
15712: } else {
15713: REG8(AH) = 0x00;
15714: REG16(BX) = ems_handles[REG16(DX)].pages;
15715: }
15716: }
15717:
15718: inline void msdos_int_67h_4dh()
15719: {
15720: if(!support_ems) {
15721: REG8(AH) = 0x84;
15722: } else {
15723: REG8(AH) = 0x00;
15724: REG16(BX) = 0;
15725: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
15726: if(ems_handles[i].allocated) {
15727: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
15728: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
15729: REG16(BX)++;
15730: }
15731: }
15732: }
15733: }
15734:
15735: inline void msdos_int_67h_4eh()
15736: {
15737: if(!support_ems) {
15738: REG8(AH) = 0x84;
15739: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
15740: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
15741: // save page map
15742: for(int i = 0; i < 4; i++) {
15743: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
15744: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
15745: }
15746: }
15747: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
15748: // restore page map
15749: for(int i = 0; i < 4; i++) {
15750: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
15751: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
15752:
15753: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
15754: ems_map_page(i, handle, page);
15755: } else {
15756: ems_unmap_page(i);
15757: }
15758: }
15759: }
15760: REG8(AH) = 0x00;
15761: } else if(REG8(AL) == 0x03) {
15762: REG8(AH) = 0x00;
15763: REG8(AL) = 4 * 4;
15764: } else {
15765: 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));
15766: REG8(AH) = 0x8f;
15767: }
15768: }
15769:
15770: inline void msdos_int_67h_4fh()
15771: {
15772: if(!support_ems) {
15773: REG8(AH) = 0x84;
15774: } else if(REG8(AL) == 0x00) {
15775: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
15776:
15777: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
15778: for(int i = 0; i < count; i++) {
15779: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
15780: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
15781:
15782: // if(!(physical < 4)) {
15783: // REG8(AH) = 0x8b;
15784: // return;
15785: // }
15786: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
15787: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].handle : 0xffff;
15788: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
15789: }
15790: REG8(AH) = 0x00;
15791: } else if(REG8(AL) == 0x01) {
15792: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
15793:
15794: for(int i = 0; i < count; i++) {
15795: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
15796: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
15797: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
15798: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
15799:
15800: // if(!(physical < 4)) {
15801: // REG8(AH) = 0x8b;
15802: // return;
15803: // } else
15804: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && logical < ems_handles[handle].pages) {
15805: ems_map_page(physical & 3, handle, logical);
15806: } else {
15807: ems_unmap_page(physical & 3);
15808: }
15809: }
15810: REG8(AH) = 0x00;
15811: } else if(REG8(AL) == 0x02) {
15812: REG8(AH) = 0x00;
15813: REG8(AL) = 2 + REG16(BX) * 6;
15814: } else {
15815: 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));
15816: REG8(AH) = 0x8f;
15817: }
15818: }
15819:
15820: inline void msdos_int_67h_50h()
15821: {
15822: if(!support_ems) {
15823: REG8(AH) = 0x84;
15824: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15825: REG8(AH) = 0x83;
15826: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
15827: for(int i = 0; i < REG16(CX); i++) {
15828: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
15829: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
15830:
15831: if(REG8(AL) == 0x01) {
15832: physical = ((physical << 4) - EMS_TOP) / 0x4000;
15833: }
15834: // if(!(physical < 4)) {
15835: // REG8(AH) = 0x8b;
15836: // return;
15837: // } else
15838: if(logical == 0xffff) {
15839: ems_unmap_page(physical & 3);
15840: } else if(logical < ems_handles[REG16(DX)].pages) {
15841: ems_map_page(physical & 3, REG16(DX), logical);
15842: } else {
15843: REG8(AH) = 0x8a;
15844: return;
15845: }
15846: }
15847: REG8(AH) = 0x00;
15848: } else {
15849: 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));
15850: REG8(AH) = 0x8f;
15851: }
15852: }
15853:
15854: inline void msdos_int_67h_51h()
15855: {
15856: if(!support_ems) {
15857: REG8(AH) = 0x84;
15858: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15859: REG8(AH) = 0x83;
15860: } else if(REG16(BX) > MAX_EMS_PAGES) {
15861: REG8(AH) = 0x87;
15862: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
15863: REG8(AH) = 0x88;
15864: } else {
15865: ems_reallocate_pages(REG16(DX), REG16(BX));
15866: REG8(AH) = 0x00;
15867: }
15868: }
15869:
15870: inline void msdos_int_67h_52h()
15871: {
15872: if(!support_ems) {
15873: REG8(AH) = 0x84;
15874: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15875: // REG8(AH) = 0x83;
15876: } else if(REG8(AL) == 0x00) {
15877: REG8(AL) = 0x00; // handle is volatile
15878: REG8(AH) = 0x00;
15879: } else if(REG8(AL) == 0x01) {
15880: if(REG8(BL) == 0x00) {
15881: REG8(AH) = 0x00;
15882: } else {
15883: REG8(AH) = 0x90; // undefined attribute type
15884: }
15885: } else if(REG8(AL) == 0x02) {
15886: REG8(AL) = 0x00; // only volatile handles supported
15887: REG8(AH) = 0x00;
15888: } else {
15889: 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));
15890: REG8(AH) = 0x8f;
15891: }
15892: }
15893:
15894: inline void msdos_int_67h_53h()
15895: {
15896: if(!support_ems) {
15897: REG8(AH) = 0x84;
15898: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15899: REG8(AH) = 0x83;
15900: } else if(REG8(AL) == 0x00) {
15901: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
15902: REG8(AH) = 0x00;
15903: } else if(REG8(AL) == 0x01) {
15904: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
15905: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
15906: REG8(AH) = 0xa1;
15907: return;
15908: }
15909: }
15910: REG8(AH) = 0x00;
15911: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
15912: } else {
15913: 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));
15914: REG8(AH) = 0x8f;
15915: }
15916: }
15917:
15918: inline void msdos_int_67h_54h()
15919: {
15920: if(!support_ems) {
15921: REG8(AH) = 0x84;
15922: } else if(REG8(AL) == 0x00) {
15923: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
15924: if(ems_handles[i].allocated) {
15925: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
15926: } else {
15927: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
15928: }
15929: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
15930: }
15931: REG8(AH) = 0x00;
15932: REG8(AL) = MAX_EMS_HANDLES;
15933: } else if(REG8(AL) == 0x01) {
15934: REG8(AH) = 0xa0; // not found
15935: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
15936: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
15937: REG8(AH) = 0x00;
15938: REG16(DX) = i;
15939: break;
15940: }
15941: }
15942: } else if(REG8(AL) == 0x02) {
15943: REG8(AH) = 0x00;
15944: REG16(BX) = MAX_EMS_HANDLES;
15945: } else {
15946: 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));
15947: REG8(AH) = 0x8f;
15948: }
15949: }
15950:
15951: inline void msdos_int_67h_55h()
15952: {
15953: if(!support_ems) {
15954: REG8(AH) = 0x84;
15955: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15956: REG8(AH) = 0x83;
15957: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
15958: UINT16 jump_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0);
15959: UINT16 jump_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2);
15960: UINT8 entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4);
15961: UINT16 map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
15962: UINT16 map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7);
15963:
15964: for(int i = 0; i < (int)entries; i++) {
15965: int logical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 0);
15966: int physical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 2);
15967:
15968: if(REG8(AL) == 0x01) {
15969: physical = ((physical << 4) - EMS_TOP) / 0x4000;
15970: }
15971: // if(!(physical < 4)) {
15972: // REG8(AH) = 0x8b;
15973: // return;
15974: // } else
15975: if(logical == 0xffff) {
15976: ems_unmap_page(physical & 3);
15977: } else if(logical < ems_handles[REG16(DX)].pages) {
15978: ems_map_page(physical & 3, REG16(DX), logical);
15979: } else {
15980: REG8(AH) = 0x8a;
15981: return;
15982: }
15983: }
15984: i386_jmp_far(jump_seg, jump_ofs);
15985: REG8(AH) = 0x00;
15986: } else {
15987: 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));
15988: REG8(AH) = 0x8f;
15989: }
15990: }
15991:
15992: inline void msdos_int_67h_56h()
15993: {
15994: if(!support_ems) {
15995: REG8(AH) = 0x84;
15996: } else if(REG8(AL) == 0x02) {
15997: REG16(BX) = (2 + 2) * 4;
15998: REG8(AH) = 0x00;
15999: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
16000: REG8(AH) = 0x83;
16001: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
16002: UINT16 call_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0);
16003: UINT16 call_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2);
16004: UINT8 new_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4);
16005: UINT16 new_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
16006: UINT16 new_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7);
16007: #if 0
16008: UINT8 old_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 9);
16009: UINT16 old_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 10);
16010: UINT16 old_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 12);
16011: #endif
16012: UINT16 handles[4], pages[4];
16013:
16014: // alter page map and call routine is at fffc:001f
16015: if(!(call_seg == 0 && call_ofs == 0)) {
16016: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far
16017: mem[DUMMY_TOP + 0x20] = (call_ofs >> 0) & 0xff;
16018: mem[DUMMY_TOP + 0x21] = (call_ofs >> 8) & 0xff;
16019: mem[DUMMY_TOP + 0x22] = (call_seg >> 0) & 0xff;
16020: mem[DUMMY_TOP + 0x23] = (call_seg >> 8) & 0xff;
16021: } else {
16022: // invalid call addr :-(
16023: mem[DUMMY_TOP + 0x1f] = 0x90; // nop
16024: mem[DUMMY_TOP + 0x20] = 0x90; // nop
16025: mem[DUMMY_TOP + 0x21] = 0x90; // nop
16026: mem[DUMMY_TOP + 0x22] = 0x90; // nop
16027: mem[DUMMY_TOP + 0x23] = 0x90; // nop
16028: }
16029: // do call far (push cs/ip) in old mapping
16030: i386_call_far(DUMMY_TOP >> 4, 0x001f);
16031:
16032: // get old mapping data
16033: #if 0
16034: for(int i = 0; i < (int)old_entries; i++) {
16035: int logical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 0);
16036: int physical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 2);
16037:
16038: if(REG8(AL) == 0x01) {
16039: physical = ((physical << 4) - EMS_TOP) / 0x4000;
16040: }
16041: // if(!(physical < 4)) {
16042: // REG8(AH) = 0x8b;
16043: // return;
16044: // } else
16045: if(logical == 0xffff) {
16046: ems_unmap_page(physical & 3);
16047: } else if(logical < ems_handles[REG16(DX)].pages) {
16048: ems_map_page(physical & 3, REG16(DX), logical);
16049: } else {
16050: REG8(AH) = 0x8a;
16051: return;
16052: }
16053: }
16054: #endif
16055: for(int i = 0; i < 4; i++) {
16056: handles[i] = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
16057: pages [i] = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
16058: }
16059:
16060: // set new mapping
16061: for(int i = 0; i < (int)new_entries; i++) {
16062: int logical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 0);
16063: int physical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 2);
16064:
16065: if(REG8(AL) == 0x01) {
16066: physical = ((physical << 4) - EMS_TOP) / 0x4000;
16067: }
16068: // if(!(physical < 4)) {
16069: // REG8(AH) = 0x8b;
16070: // return;
16071: // } else
16072: if(logical == 0xffff) {
16073: ems_unmap_page(physical & 3);
16074: } else if(logical < ems_handles[REG16(DX)].pages) {
16075: ems_map_page(physical & 3, REG16(DX), logical);
16076: } else {
16077: REG8(AH) = 0x8a;
16078: return;
16079: }
16080: }
16081:
16082: // push old mapping data in new mapping
16083: for(int i = 0; i < 4; i++) {
16084: i386_push16(handles[i]);
16085: i386_push16(pages [i]);
16086: }
16087: REG8(AH) = 0x00;
16088: } else {
16089: 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));
16090: REG8(AH) = 0x8f;
16091: }
16092: }
16093:
16094: inline void msdos_int_67h_57h_tmp()
16095: {
16096: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
16097: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
16098: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
16099: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
16100: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
16101: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
16102: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
16103: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
16104: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
16105:
16106: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
16107: UINT32 src_addr, dest_addr;
16108: UINT32 src_addr_max, dest_addr_max;
16109:
16110: if(src_type == 0) {
16111: src_buffer = mem;
16112: src_addr = (src_seg << 4) + src_ofs;
16113: src_addr_max = MAX_MEM;
16114: } else {
16115: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
16116: REG8(AH) = 0x83;
16117: return;
16118: } else if(!(src_seg < ems_handles[src_handle].pages)) {
16119: REG8(AH) = 0x8a;
16120: return;
16121: }
16122: if(ems_handles[src_handle].buffer != NULL) {
16123: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
16124: }
16125: src_addr = src_ofs;
16126: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
16127: }
16128: if(dest_type == 0) {
16129: dest_buffer = mem;
16130: dest_addr = (dest_seg << 4) + dest_ofs;
16131: dest_addr_max = MAX_MEM;
16132: } else {
16133: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
16134: REG8(AH) = 0x83;
16135: return;
16136: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
16137: REG8(AH) = 0x8a;
16138: return;
16139: }
16140: if(ems_handles[dest_handle].buffer != NULL) {
16141: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
16142: }
16143: dest_addr = dest_ofs;
16144: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
16145: }
16146: if(src_buffer != NULL && dest_buffer != NULL) {
16147: for(int i = 0; i < copy_length; i++) {
16148: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
16149: if(REG8(AL) == 0x00) {
16150: dest_buffer[dest_addr++] = src_buffer[src_addr++];
16151: } else if(REG8(AL) == 0x01) {
16152: UINT8 tmp = dest_buffer[dest_addr];
16153: dest_buffer[dest_addr++] = src_buffer[src_addr];
16154: src_buffer[src_addr++] = tmp;
16155: }
16156: } else {
16157: REG8(AH) = 0x93;
16158: return;
16159: }
16160: }
16161: REG8(AH) = 0x00;
16162: } else {
16163: REG8(AH) = 0x80;
16164: }
16165: }
16166:
16167: inline void msdos_int_67h_57h()
16168: {
16169: if(!support_ems) {
16170: REG8(AH) = 0x84;
16171: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
16172: struct {
16173: UINT16 handle;
16174: UINT16 page;
16175: bool mapped;
16176: } tmp_pages[4];
16177:
16178: // unmap pages to copy memory data to ems buffer
16179: for(int i = 0; i < 4; i++) {
16180: tmp_pages[i].handle = ems_pages[i].handle;
16181: tmp_pages[i].page = ems_pages[i].page;
16182: tmp_pages[i].mapped = ems_pages[i].mapped;
16183: ems_unmap_page(i);
16184: }
16185:
16186: // run move/exchange operation
16187: msdos_int_67h_57h_tmp();
16188:
16189: // restore unmapped pages
16190: for(int i = 0; i < 4; i++) {
16191: if(tmp_pages[i].mapped) {
16192: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
16193: }
16194: }
16195: } else {
16196: 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));
16197: REG8(AH) = 0x8f;
16198: }
16199: }
16200:
16201: inline void msdos_int_67h_58h()
16202: {
16203: if(!support_ems) {
16204: REG8(AH) = 0x84;
16205: } else if(REG8(AL) == 0x00) {
16206: for(int i = 0; i < 4; i++) {
16207: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
16208: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
16209: }
16210: REG8(AH) = 0x00;
16211: REG16(CX) = 4;
16212: } else if(REG8(AL) == 0x01) {
16213: REG8(AH) = 0x00;
16214: REG16(CX) = 4;
16215: } else {
16216: 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));
16217: REG8(AH) = 0x8f;
16218: }
16219: }
16220:
16221: inline void msdos_int_67h_59h()
16222: {
16223: if(!support_ems) {
16224: REG8(AH) = 0x84;
16225: } else if(REG8(AL) == 0x00) {
16226: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1024;
16227: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 0;
16228: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 4 * 4;
16229: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = 0;
16230: REG8(AH) = 0x00;
16231: // REG8(AH) = 0xa4; // access denied by operating system
16232: } else if(REG8(AL) == 0x01) {
16233: REG8(AH) = 0x00;
16234: REG16(BX) = free_ems_pages;
16235: REG16(DX) = MAX_EMS_PAGES;
16236: } else {
16237: 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));
16238: REG8(AH) = 0x8f;
16239: }
16240: }
16241:
16242: inline void msdos_int_67h_5ah()
16243: {
16244: if(!support_ems) {
16245: REG8(AH) = 0x84;
16246: } else if(REG16(BX) > MAX_EMS_PAGES) {
16247: REG8(AH) = 0x87;
16248: } else if(REG16(BX) > free_ems_pages) {
16249: REG8(AH) = 0x88;
16250: // } else if(REG16(BX) == 0) {
16251: // REG8(AH) = 0x89;
16252: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
16253: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
16254: if(!ems_handles[i].allocated) {
16255: ems_allocate_pages(i, REG16(BX));
16256: REG8(AH) = 0x00;
16257: REG16(DX) = i;
16258: return;
16259: }
16260: }
16261: REG8(AH) = 0x85;
16262: } else {
16263: 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));
16264: REG8(AH) = 0x8f;
16265: }
16266: }
16267:
16268: inline void msdos_int_67h_5bh()
16269: {
16270: static UINT8 stored_bl = 0x00;
16271: static UINT16 stored_es = 0x0000;
16272: static UINT16 stored_di = 0x0000;
16273:
16274: if(!support_ems) {
16275: REG8(AH) = 0x84;
16276: } else if(REG8(AL) == 0x00) {
16277: if(stored_bl == 0x00) {
16278: if(!(stored_es == 0 && stored_di == 0)) {
16279: for(int i = 0; i < 4; i++) {
16280: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
16281: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
16282: }
16283: }
16284: SREG(ES) = stored_es;
16285: i386_load_segment_descriptor(ES);
16286: REG16(DI) = stored_di;
16287: } else {
16288: REG8(BL) = stored_bl;
16289: }
16290: REG8(AH) = 0x00;
16291: } else if(REG8(AL) == 0x01) {
16292: if(REG8(BL) == 0x00) {
16293: if(!(SREG(ES) == 0 && REG16(DI) == 0)) {
16294: for(int i = 0; i < 4; i++) {
16295: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0);
16296: UINT16 page = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2);
16297:
16298: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
16299: ems_map_page(i, handle, page);
16300: } else {
16301: ems_unmap_page(i);
16302: }
16303: }
16304: }
16305: }
16306: stored_bl = REG8(BL);
16307: stored_es = SREG(ES);
16308: stored_di = REG16(DI);
16309: REG8(AH) = 0x00;
16310: } else if(REG8(AL) == 0x02) {
16311: REG16(DX) = 4 * 4;
16312: REG8(AH) = 0x00;
16313: } else if(REG8(AL) == 0x03) {
16314: REG8(BL) = 0x00; // not supported
16315: REG8(AH) = 0x00;
16316: } else if(REG8(AL) == 0x04) {
16317: REG8(AH) = 0x00;
16318: } else if(REG8(AL) == 0x05) {
16319: REG8(BL) = 0x00; // not supported
16320: REG8(AH) = 0x00;
16321: } else {
16322: 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));
16323: REG8(AH) = 0x8f;
16324: }
16325: }
16326:
16327: inline void msdos_int_67h_5dh()
16328: {
16329: if(!support_ems) {
16330: REG8(AH) = 0x84;
16331: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
16332: REG8(AH) = 0xa4; // operating system denied access
16333: } else {
16334: 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));
16335: REG8(AH) = 0x8f;
16336: }
16337: }
16338:
16339: inline void msdos_int_67h_70h()
16340: {
16341: if(!support_ems) {
16342: REG8(AH) = 0x84;
16343: } else if(REG8(AL) == 0x00) {
16344: REG8(AL) = 0x00;
16345: REG8(AH) = 0x00;
16346: } else if(REG8(AL) == 0x01) {
16347: REG8(AL) = 0x00;
16348: // REG8(AH) = (REG8(BL) == 0x00) ? 0x00 : 0x80;
16349: REG8(AH) = 0x00;
16350: } else {
16351: 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));
16352: REG8(AH) = 0x8f;
16353: }
16354: }
16355:
16356: inline void msdos_int_67h_deh()
16357: {
16358: #if defined(SUPPORT_VCPI)
16359: if(!support_ems) {
16360: REG8(AH) = 0x84;
16361: } else if(REG8(AL) == 0x00) {
16362: REG8(AH) = 0x00;
16363: REG16(BX) = 0x0100;
16364: } else if(REG8(AL) == 0x01) {
16365: REG8(AH) = 0x00;
16366: // from DOSBox
16367: for(int ct = 0; ct < 0xff; ct++) {
16368: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x00) = 0x67; // access bits
16369: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x01) = ct * 0x10; // mapping
16370: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x03) = 0x00;
16371: }
16372: for(int ct = 0xff; ct < 0x100; ct++) {
16373: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x00) = 0x67; // access bits
16374: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x01) = (ct - 0xff) * 0x10 + 0x1100; // mapping
16375: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x03) = 0x00;
16376: }
16377: REG16(DI) += 0x400; // advance pointer by 0x100*4
16378:
16379: // Set up three descriptor table entries
16380: UINT32 cbseg_low = (DUMMY_TOP & 0x00ffff) << 16;
16381: UINT32 cbseg_high = (DUMMY_TOP & 0x1f0000) >> 16;
16382: // Descriptor 1 (code segment, callback segment)
16383: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x0000ffff | cbseg_low ;
16384: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = 0x00009a00 | cbseg_high;
16385: // Descriptor 2 (data segment, full access)
16386: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x08) = 0x0000ffff;
16387: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c) = 0x00009200;
16388: // Descriptor 3 (full access)
16389: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10) = 0x0000ffff;
16390: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x14) = 0x00009200;
16391: // Offset in code segment of protected mode entry point
16392: REG32(EBX) = 0x2a; // fffc:002a
16393: } else if(REG8(AL) == 0x02) {
16394: REG8(AH) = 0x00;
16395: REG32(EDX) = (MAX_MEM - 1) & 0xfffff000;
16396: } else if(REG8(AL) == 0x03) {
16397: REG8(AH) = 0x00;
16398: REG32(EDX) = 0;
16399: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
16400: if(emb_handle->handle == 0) {
16401: REG32(EDX) += emb_handle->size_kb;
16402: }
16403: }
16404: REG32(EDX) /= 4;
16405: } else if(REG8(AL) == 0x04) {
16406: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(4);
16407: if(emb_handle != NULL) {
16408: REG8(AH) = 0x00;
16409: REG32(EDX) = emb_handle->address;
16410: }
16411: } else if(REG8(AL) == 0x05) {
16412: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
16413: if(emb_handle->handle != 0 && emb_handle->address == REG32(EDX)) {
16414: REG8(AH) = 0x00;
16415: msdos_xms_free_emb_handle(emb_handle);
16416: break;
16417: }
16418: }
16419: } else if(REG8(AL) == 0x06) {
16420: REG8(AH) = 0x00;
16421: REG32(EDX) = REG16(CX) << 12;
16422: } else if(REG8(AL) == 0x07) {
16423: REG8(AH) = 0x00;
16424: REG32(EBX) = m_cr[0];
16425: } else if(REG8(AL) == 0x08) {
16426: REG8(AH) = 0x00;
16427: for(int i = 0; i < 8; i++) {
16428: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i) = m_dr[i];
16429: }
16430: } else if(REG8(AL) == 0x09) {
16431: REG8(AH) = 0x00;
16432: for(int i = 0; i < 8; i++) {
16433: m_dr[i] = *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i);
16434: }
16435: } else if(REG8(AL) == 0x0a) {
16436: REG8(AH) = 0x00;
16437: REG16(BX) = pic[0].icw2;
16438: REG16(CX) = pic[1].icw2;
16439: } else if(REG8(AL) == 0x0b) {
16440: REG8(AH) = 0x00;
16441: pic[0].icw2 = REG8(BL);
16442: pic[1].icw2 = REG8(CL);
16443: } else if(REG8(AL) == 0x0c) {
16444: // from DOSBox
16445: m_IF = 0;
16446: m_CPL = 0;
16447:
16448: // Read data from ESI (linear address)
16449: UINT32 new_cr3 = *(UINT32 *)(mem + REG32(ESI) + 0x00);
16450: UINT32 new_gdt_addr = *(UINT32 *)(mem + REG32(ESI) + 0x04);
16451: UINT32 new_idt_addr = *(UINT32 *)(mem + REG32(ESI) + 0x08);
16452: UINT16 new_ldt = *(UINT16 *)(mem + REG32(ESI) + 0x0c);
16453: UINT16 new_tr = *(UINT16 *)(mem + REG32(ESI) + 0x0e);
16454: UINT32 new_eip = *(UINT32 *)(mem + REG32(ESI) + 0x10);
16455: UINT16 new_cs = *(UINT16 *)(mem + REG32(ESI) + 0x14);
16456:
16457: // Get GDT and IDT entries
16458: UINT16 new_gdt_limit = *(UINT16 *)(mem + new_gdt_addr + 0);
16459: UINT32 new_gdt_base = *(UINT32 *)(mem + new_gdt_addr + 2);
16460: UINT16 new_idt_limit = *(UINT16 *)(mem + new_idt_addr + 0);
16461: UINT32 new_idt_base = *(UINT32 *)(mem + new_idt_addr + 2);
16462:
16463: // Switch to protected mode, paging enabled if necessary
16464: if(new_cr3 != 0) {
16465: m_cr[0] |= 0x80000000;
16466: }
16467: m_cr[3] = new_cr3;
16468:
16469: *(UINT8 *)(mem + new_gdt_base + (new_tr & 0xfff8) + 5) &= 0xfd;
16470:
16471: // Load tables and initialize segment registers
16472: m_gdtr.limit = new_gdt_limit;
16473: m_gdtr.base = new_gdt_base;
16474: m_idtr.limit = new_idt_limit;
16475: m_idtr.base = new_idt_base;
16476:
16477: i386_sreg_load(0x00, DS, NULL);
16478: i386_sreg_load(0x00, ES, NULL);
16479: i386_sreg_load(0x00, FS, NULL);
16480: i386_sreg_load(0x00, GS, NULL);
16481:
16482: // i386_set_a20_line(1);
16483:
16484: /* Switch to protected mode */
16485: m_VM = m_NT = 0;
16486: m_IOP1 = m_IOP2 = 1;
16487:
16488: i386_jmp_far(new_cs, new_eip);
16489: } else {
16490: 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));
16491: REG8(AH) = 0x8f;
16492: }
16493: #else
16494: REG8(AH) = 0x84;
16495: #endif
16496: }
16497:
16498: #ifdef SUPPORT_XMS
16499:
16500: void msdos_xms_init()
16501: {
16502: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
16503: emb_handle_top->address = EMB_TOP;
16504: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
16505: xms_a20_local_enb_count = 0;
16506: }
16507:
16508: void msdos_xms_finish()
16509: {
16510: msdos_xms_release();
16511: }
16512:
16513: void msdos_xms_release()
16514: {
16515: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
16516: emb_handle_t *next_handle = emb_handle->next;
16517: free(emb_handle);
16518: emb_handle = next_handle;
16519: }
16520: }
16521:
16522: emb_handle_t *msdos_xms_get_emb_handle(int handle)
16523: {
16524: if(handle != 0) {
16525: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
16526: if(emb_handle->handle == handle) {
16527: return(emb_handle);
16528: }
16529: }
16530: }
16531: return(NULL);
16532: }
16533:
16534: int msdos_xms_get_unused_emb_handle_id()
16535: {
16536: for(int handle = 1;; handle++) {
16537: if(msdos_xms_get_emb_handle(handle) == NULL) {
16538: return(handle);
16539: }
16540: }
16541: return(0);
16542: }
16543:
16544: int msdos_xms_get_unused_emb_handle_count()
16545: {
16546: int count = 64; //255;
16547:
16548: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
16549: if(emb_handle->handle != 0) {
16550: if(--count == 1) {
16551: break;
16552: }
16553: }
16554: }
16555: return(count);
16556: }
16557:
16558: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
16559: {
16560: if(emb_handle->size_kb > size_kb) {
16561: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
16562:
16563: new_handle->address = emb_handle->address + size_kb * 1024;
16564: new_handle->size_kb = emb_handle->size_kb - size_kb;
16565: emb_handle->size_kb = size_kb;
16566:
16567: new_handle->prev = emb_handle;
16568: new_handle->next = emb_handle->next;
16569: if(emb_handle->next != NULL) {
16570: emb_handle->next->prev = new_handle;
16571: }
16572: emb_handle->next = new_handle;
16573: }
16574: }
16575:
16576: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
16577: {
16578: emb_handle_t *next_handle = emb_handle->next;
16579:
16580: if(next_handle != NULL) {
16581: emb_handle->size_kb += next_handle->size_kb;
16582:
16583: if(next_handle->next != NULL) {
16584: next_handle->next->prev = emb_handle;
16585: }
16586: emb_handle->next = next_handle->next;
16587: free(next_handle);
16588: }
16589: }
16590:
16591: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
16592: {
16593: emb_handle_t *target_handle = NULL;
16594:
16595: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
16596: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
16597: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
16598: target_handle = emb_handle;
16599: }
16600: }
16601: }
16602: if(target_handle != NULL) {
16603: if(target_handle->size_kb > size_kb) {
16604: msdos_xms_split_emb_handle(target_handle, size_kb);
16605: }
16606: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
16607: return(target_handle);
16608: }
16609: return(NULL);
16610: }
16611:
16612: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
16613: {
16614: emb_handle_t *prev_handle = emb_handle->prev;
16615: emb_handle_t *next_handle = emb_handle->next;
16616:
16617: if(prev_handle != NULL && prev_handle->handle == 0) {
16618: msdos_xms_combine_emb_handles(prev_handle);
16619: emb_handle = prev_handle;
16620: }
16621: if(next_handle != NULL && next_handle->handle == 0) {
16622: msdos_xms_combine_emb_handles(emb_handle);
16623: }
16624: emb_handle->handle = 0;
16625: }
16626:
16627: inline void msdos_call_xms_00h()
16628: {
16629: #if defined(HAS_I386)
16630: REG16(AX) = 0x0300; // V3.00 (XMS Version)
16631: REG16(BX) = 0x0395; // V3.95 (Driver Revision in BCD)
16632: // REG16(BX) = 0x035f; // V3.95 (Driver Revision)
16633: #else
16634: REG16(AX) = 0x0200; // V2.00 (XMS Version)
16635: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
16636: #endif
16637: // REG16(DX) = 0x0000; // HMA does not exist
16638: REG16(DX) = 0x0001; // HMA does exist
16639: }
16640:
16641: inline void msdos_call_xms_01h()
16642: {
16643: if(REG8(AL) == 0x40) {
16644: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
16645: // DX=KB free extended memory returned by last call of function 08h
16646: REG16(AX) = 0x0000;
16647: REG8(BL) = 0x91;
16648: REG16(DX) = xms_dx_after_call_08h;
16649: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
16650: REG16(AX) = 0x0000;
16651: REG8(BL) = 0x81; // Vdisk was detected
16652: #ifdef SUPPORT_HMA
16653: } else if(is_hma_used_by_int_2fh) {
16654: REG16(AX) = 0x0000;
16655: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
16656: } else if(is_hma_used_by_xms) {
16657: REG16(AX) = 0x0000;
16658: REG8(BL) = 0x91; // HMA is already in use
16659: } else {
16660: REG16(AX) = 0x0001;
16661: is_hma_used_by_xms = true;
16662: #else
16663: } else {
16664: REG16(AX) = 0x0000;
16665: REG8(BL) = 0x91; // HMA is already in use
16666: #endif
16667: }
16668: }
16669:
16670: inline void msdos_call_xms_02h()
16671: {
16672: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
16673: REG16(AX) = 0x0000;
16674: REG8(BL) = 0x81; // Vdisk was detected
16675: #ifdef SUPPORT_HMA
16676: } else if(is_hma_used_by_int_2fh) {
16677: REG16(AX) = 0x0000;
16678: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
16679: } else if(!is_hma_used_by_xms) {
16680: REG16(AX) = 0x0000;
16681: REG8(BL) = 0x93; // HMA is not allocated
16682: } else {
16683: REG16(AX) = 0x0001;
16684: is_hma_used_by_xms = false;
16685: // restore first free mcb in high memory area
16686: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
16687: #else
16688: } else {
16689: REG16(AX) = 0x0000;
16690: REG8(BL) = 0x91; // HMA is already in use
16691: #endif
16692: }
16693: }
16694:
16695: inline void msdos_call_xms_03h()
16696: {
16697: i386_set_a20_line(1);
16698: REG16(AX) = 0x0001;
16699: REG8(BL) = 0x00;
16700: }
16701:
16702: inline void msdos_call_xms_04h()
16703: {
16704: i386_set_a20_line(0);
16705: REG16(AX) = 0x0001;
16706: REG8(BL) = 0x00;
16707: }
16708:
16709: inline void msdos_call_xms_05h()
16710: {
16711: i386_set_a20_line(1);
16712: REG16(AX) = 0x0001;
16713: REG8(BL) = 0x00;
16714: xms_a20_local_enb_count++;
16715: }
16716:
16717: void msdos_call_xms_06h()
16718: {
16719: if(xms_a20_local_enb_count > 0) {
16720: if(--xms_a20_local_enb_count == 0) {
16721: i386_set_a20_line(0);
16722: REG16(AX) = 0x0001;
16723: REG8(BL) = 0x00;
16724: } else {
16725: REG16(AX) = 0x0000;
16726: REG8(BL) = 0x94;
16727: }
16728: } else {
16729: i386_set_a20_line(0);
16730: REG16(AX) = 0x0001;
16731: REG8(BL) = 0x00;
16732: }
16733: }
16734:
16735: inline void msdos_call_xms_07h()
16736: {
16737: REG16(AX) = (m_a20_mask >> 20) & 1;
16738: REG8(BL) = 0x00;
16739: }
16740:
16741: inline void msdos_call_xms_08h()
16742: {
16743: UINT32 eax = 0, edx = 0;
16744:
16745: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
16746: if(emb_handle->handle == 0) {
16747: if(eax < emb_handle->size_kb) {
16748: eax = emb_handle->size_kb;
16749: }
16750: edx += emb_handle->size_kb;
16751: }
16752: }
16753: if(eax > 65535) {
16754: eax = 65535;
16755: }
16756: if(edx > 65535) {
16757: edx = 65535;
16758: }
16759: if(eax == 0 && edx == 0) {
16760: REG8(BL) = 0xa0;
16761: } else {
16762: REG8(BL) = 0x00;
16763: }
16764: #if defined(HAS_I386)
16765: REG32(EAX) = eax;
16766: REG32(EDX) = edx;
16767: #else
16768: REG16(AX) = (UINT16)eax;
16769: REG16(DX) = (UINT16)edx;
16770: #endif
16771: xms_dx_after_call_08h = REG16(DX);
16772: }
16773:
16774: void msdos_call_xms_09h(int size_kb)
16775: {
16776: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
16777:
16778: if(emb_handle != NULL) {
16779: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
16780:
16781: REG16(AX) = 0x0001;
16782: REG16(DX) = emb_handle->handle;
16783: REG8(BL) = 0x00;
16784: } else {
16785: REG16(AX) = REG16(DX) = 0x0000;
16786: REG8(BL) = 0xa0;
16787: }
16788: }
16789:
16790: inline void msdos_call_xms_09h()
16791: {
16792: msdos_call_xms_09h(REG16(DX));
16793: }
16794:
16795: inline void msdos_call_xms_0ah()
16796: {
16797: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16798:
16799: if(emb_handle == NULL) {
16800: REG16(AX) = 0x0000;
16801: REG8(BL) = 0xa2;
16802: // } else if(emb_handle->lock > 0) {
16803: // REG16(AX) = 0x0000;
16804: // REG8(BL) = 0xab;
16805: } else {
16806: msdos_xms_free_emb_handle(emb_handle);
16807:
16808: REG16(AX) = 0x0001;
16809: REG8(BL) = 0x00;
16810: }
16811: }
16812:
16813: inline void msdos_call_xms_0bh()
16814: {
16815: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
16816: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
16817: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
16818: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
16819: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
16820:
16821: UINT8 *src_buffer, *dest_buffer;
16822: UINT32 src_addr_max, dest_addr_max;
16823: emb_handle_t *emb_handle;
16824:
16825: if(src_handle == 0) {
16826: src_buffer = mem;
16827: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
16828: src_addr_max = MAX_MEM;
16829: } else {
16830: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
16831: REG16(AX) = 0x0000;
16832: REG8(BL) = 0xa3;
16833: return;
16834: }
16835: src_buffer = mem + emb_handle->address;
16836: src_addr_max = emb_handle->size_kb * 1024;
16837: }
16838: if(dest_handle == 0) {
16839: dest_buffer = mem;
16840: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
16841: dest_addr_max = MAX_MEM;
16842: } else {
16843: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
16844: REG16(AX) = 0x0000;
16845: REG8(BL) = 0xa5;
16846: return;
16847: }
16848: dest_buffer = mem + emb_handle->address;
16849: dest_addr_max = emb_handle->size_kb * 1024;
16850: }
16851: for(int i = 0; i < copy_length; i++) {
16852: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
16853: dest_buffer[dest_addr++] = src_buffer[src_addr++];
16854: } else {
16855: break;
16856: }
16857: }
16858: REG16(AX) = 0x0001;
16859: REG8(BL) = 0x00;
16860: }
16861:
16862: inline void msdos_call_xms_0ch()
16863: {
16864: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16865:
16866: if(emb_handle == NULL) {
16867: REG16(AX) = 0x0000;
16868: REG8(BL) = 0xa2;
16869: } else {
16870: if(emb_handle->lock < 255) {
16871: emb_handle->lock++;
16872: }
16873: REG16(AX) = 0x0001;
16874: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
16875: REG16(BX) = (emb_handle->address ) & 0xffff;
16876: }
16877: }
16878:
16879: inline void msdos_call_xms_0dh()
16880: {
16881: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16882:
16883: if(emb_handle == NULL) {
16884: REG16(AX) = 0x0000;
16885: REG8(BL) = 0xa2;
16886: } else if(!(emb_handle->lock > 0)) {
16887: REG16(AX) = 0x0000;
16888: REG8(BL) = 0xaa;
16889: } else {
16890: emb_handle->lock--;
16891: REG16(AX) = 0x0001;
16892: REG8(BL) = 0x00;
16893: }
16894: }
16895:
16896: inline void msdos_call_xms_0eh()
16897: {
16898: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16899:
16900: if(emb_handle == NULL) {
16901: REG16(AX) = 0x0000;
16902: REG8(BL) = 0xa2;
16903: } else {
16904: REG16(AX) = 0x0001;
16905: REG8(BH) = emb_handle->lock;
16906: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
16907: REG16(DX) = emb_handle->size_kb;
16908: }
16909: }
16910:
16911: void msdos_call_xms_0fh(int size_kb)
16912: {
16913: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16914:
16915: if(emb_handle == NULL) {
16916: REG16(AX) = 0x0000;
16917: REG8(BL) = 0xa2;
16918: } else if(emb_handle->lock > 0) {
16919: REG16(AX) = 0x0000;
16920: REG8(BL) = 0xab;
16921: } else {
16922: if(emb_handle->size_kb < size_kb) {
16923: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
16924: msdos_xms_combine_emb_handles(emb_handle);
16925: if(emb_handle->size_kb > size_kb) {
16926: msdos_xms_split_emb_handle(emb_handle, size_kb);
16927: }
16928: } else {
16929: int old_handle = emb_handle->handle;
16930: int old_size_kb = emb_handle->size_kb;
16931: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
16932:
16933: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
16934: msdos_xms_free_emb_handle(emb_handle);
16935:
16936: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
16937: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
16938: }
16939: emb_handle->handle = old_handle;
16940: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
16941: free(buffer);
16942: }
16943: } else if(emb_handle->size_kb > size_kb) {
16944: msdos_xms_split_emb_handle(emb_handle, size_kb);
16945: }
16946: if(emb_handle->size_kb != size_kb) {
16947: REG16(AX) = 0x0000;
16948: REG8(BL) = 0xa0;
16949: } else {
16950: REG16(AX) = 0x0001;
16951: REG8(BL) = 0x00;
16952: }
16953: }
16954: }
16955:
16956: inline void msdos_call_xms_0fh()
16957: {
16958: msdos_call_xms_0fh(REG16(BX));
16959: }
16960:
16961: inline void msdos_call_xms_10h()
16962: {
16963: int seg;
16964:
16965: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
16966: REG16(AX) = 0x0001;
16967: REG16(BX) = seg;
16968: } else {
16969: REG16(AX) = 0x0000;
16970: REG8(BL) = 0xb0;
16971: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
16972: }
16973: }
16974:
16975: inline void msdos_call_xms_11h()
16976: {
16977: int mcb_seg = REG16(DX) - 1;
16978: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
16979:
16980: if(mcb->mz == 'M' || mcb->mz == 'Z') {
16981: msdos_mem_free(REG16(DX));
16982: REG16(AX) = 0x0001;
16983: REG8(BL) = 0x00;
16984: } else {
16985: REG16(AX) = 0x0000;
16986: REG8(BL) = 0xb2;
16987: }
16988: }
16989:
16990: inline void msdos_call_xms_12h()
16991: {
16992: int mcb_seg = REG16(DX) - 1;
16993: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
16994: int max_paragraphs;
16995:
16996: if(mcb->mz == 'M' || mcb->mz == 'Z') {
16997: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
16998: REG16(AX) = 0x0001;
16999: REG8(BL) = 0x00;
17000: } else {
17001: REG16(AX) = 0x0000;
17002: REG8(BL) = 0xb0;
17003: REG16(DX) = max_paragraphs;
17004: }
17005: } else {
17006: REG16(AX) = 0x0000;
17007: REG8(BL) = 0xb2;
17008: }
17009: }
17010:
17011: #if defined(HAS_I386)
17012:
17013: inline void msdos_call_xms_88h()
17014: {
17015: REG32(EAX) = REG32(EDX) = 0x0000;
17016:
17017: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
17018: if(emb_handle->handle == 0) {
17019: if(REG32(EAX) < emb_handle->size_kb) {
17020: REG32(EAX) = emb_handle->size_kb;
17021: }
17022: REG32(EDX) += emb_handle->size_kb;
17023: }
17024: }
17025: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
17026: REG8(BL) = 0xa0;
17027: } else {
17028: REG8(BL) = 0x00;
17029: }
17030: REG32(ECX) = EMB_END - 1;
17031: }
17032:
17033: inline void msdos_call_xms_89h()
17034: {
17035: msdos_call_xms_09h(REG32(EDX));
17036: }
17037:
17038: inline void msdos_call_xms_8eh()
17039: {
17040: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
17041:
17042: if(emb_handle == NULL) {
17043: REG16(AX) = 0x0000;
17044: REG8(BL) = 0xa2;
17045: } else {
17046: REG16(AX) = 0x0001;
17047: REG8(BH) = emb_handle->lock;
17048: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
17049: REG32(EDX) = emb_handle->size_kb;
17050: }
17051: }
17052:
17053: inline void msdos_call_xms_8fh()
17054: {
17055: msdos_call_xms_0fh(REG32(EBX));
17056: }
17057:
17058: #endif
17059: #endif
17060:
17061: UINT16 msdos_get_equipment()
17062: {
17063: static UINT16 equip = 0;
17064:
17065: if(equip == 0) {
17066: #ifdef SUPPORT_FPU
17067: equip |= (1 << 1); // 80x87 coprocessor installed
17068: #endif
17069: equip |= (1 << 2); // pointing device installed (PS/2)
17070: equip |= (2 << 4); // initial video mode (80x25 color)
17071: // equip |= (1 << 8); // 0 if DMA installed
17072: equip |= (2 << 9); // number of serial ports
17073: equip |= (3 << 14); // number of printer ports (NOTE: this number is 3 on Windows 98 SE though only LPT1 exists)
17074:
17075: // check only A: and B: if it is floppy drive
17076: int n = 0;
17077: for(int i = 0; i < 2; i++) {
17078: if(msdos_is_valid_drive(i) && msdos_is_removable_drive(i)) {
17079: n++;
17080: }
17081: }
17082: if(n != 0) {
17083: equip |= (1 << 0); // floppy disk(s) installed
17084: n--;
17085: equip |= (n << 6); // number of floppies installed less 1
17086: }
17087: // if(joyGetNumDevs() != 0) {
17088: // equip |= (1 << 12); // game port installed
17089: // }
17090: }
17091: return(equip);
17092: }
17093:
17094: void msdos_syscall(unsigned num)
17095: {
17096: #ifdef ENABLE_DEBUG_SYSCALL
17097: if(num == 0x08 || num == 0x1c) {
17098: // don't log the timer interrupts
17099: // fprintf(fp_debug_log, "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));
17100: } else if(num == 0x30) {
17101: // dummy interrupt for call 0005h (call near)
17102: fprintf(fp_debug_log, "call 0005h (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));
17103: } else if(num == 0x65) {
17104: // dummy interrupt for EMS (int 67h)
17105: fprintf(fp_debug_log, "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));
17106: } else if(num == 0x66) {
17107: // dummy interrupt for XMS (call far)
17108: fprintf(fp_debug_log, "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));
17109: } else if(num >= 0x68 && num <= 0x6f) {
17110: // dummy interrupt
17111: } else {
17112: fprintf(fp_debug_log, "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));
17113: }
17114: #endif
17115: // update cursor position
17116: if(cursor_moved) {
17117: pcbios_update_cursor_position();
17118: cursor_moved = false;
17119: }
17120: #ifdef USE_SERVICE_THREAD
17121: // this is called from dummy loop to wait until a serive that waits input is done
17122: if(!in_service)
17123: #endif
17124: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
17125:
17126: switch(num) {
17127: case 0x00:
17128: try {
17129: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
17130: error("division by zero\n");
17131: } catch(...) {
17132: fatalerror("division by zero detected, and failed to terminate current process\n");
17133: }
17134: break;
17135: case 0x04:
17136: try {
17137: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
17138: error("overflow\n");
17139: } catch(...) {
17140: fatalerror("overflow detected, and failed to terminate current process\n");
17141: }
17142: break;
17143: case 0x06:
17144: // NOTE: ish.com has illegal instruction...
17145: if(!ignore_illegal_insn) {
17146: try {
17147: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
17148: error("illegal instruction\n");
17149: } catch(...) {
17150: fatalerror("illegal instruction detected, and failed to terminate current process\n");
17151: }
17152: } else {
17153: #if defined(HAS_I386)
17154: m_eip = m_int6h_skip_eip;
17155: #elif defined(HAS_I286)
17156: m_pc = m_int6h_skip_pc;
17157: #else
17158: // 8086/80186 ignore an invalid opcode
17159: #endif
17160: }
17161: break;
17162: case 0x09:
17163: // ctrl-break is pressed
17164: if(raise_int_1bh) {
17165: #if defined(HAS_I386)
17166: m_ext = 0; // not an external interrupt
17167: i386_trap(0x1b, 1, 0);
17168: m_ext = 1;
17169: #else
17170: PREFIX86(_interrupt)(0x1b);
17171: #endif
17172: raise_int_1bh = false;
17173: }
17174: case 0x08:
17175: // pcbios_irq0(); // this causes too slow emulation...
17176: case 0x0b:
17177: case 0x0c:
17178: case 0x0d:
17179: case 0x0e:
17180: case 0x0f:
17181: // EOI
17182: pic[0].isr &= ~(1 << (num - 0x08));
17183: pic_update();
17184: break;
17185: case 0x10:
17186: // PC BIOS - Video
17187: if(!restore_console_on_exit) {
17188: change_console_size(scr_width, scr_height);
17189: }
17190: m_CF = 0;
17191: switch(REG8(AH)) {
17192: case 0x00: pcbios_int_10h_00h(); break;
17193: case 0x01: pcbios_int_10h_01h(); break;
17194: case 0x02: pcbios_int_10h_02h(); break;
17195: case 0x03: pcbios_int_10h_03h(); break;
17196: case 0x05: pcbios_int_10h_05h(); break;
17197: case 0x06: pcbios_int_10h_06h(); break;
17198: case 0x07: pcbios_int_10h_07h(); break;
17199: case 0x08: pcbios_int_10h_08h(); break;
17200: case 0x09: pcbios_int_10h_09h(); break;
17201: case 0x0a: pcbios_int_10h_0ah(); break;
17202: case 0x0b: break;
17203: case 0x0c: pcbios_int_10h_0ch(); break;
17204: case 0x0d: pcbios_int_10h_0dh(); break;
17205: case 0x0e: pcbios_int_10h_0eh(); break;
17206: case 0x0f: pcbios_int_10h_0fh(); break;
17207: case 0x10: break;
17208: case 0x11: pcbios_int_10h_11h(); break;
17209: case 0x12: pcbios_int_10h_12h(); break;
17210: case 0x13: pcbios_int_10h_13h(); break;
17211: case 0x18: pcbios_int_10h_18h(); break;
17212: case 0x1a: pcbios_int_10h_1ah(); break;
17213: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
17214: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
17215: case 0x1d: pcbios_int_10h_1dh(); break;
17216: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
17217: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
17218: case 0x4f: pcbios_int_10h_4fh(); break;
17219: case 0x6f: break;
17220: case 0x80: m_CF = 1; break; // unknown
17221: case 0x81: m_CF = 1; break; // unknown
17222: case 0x82: pcbios_int_10h_82h(); break;
17223: case 0x83: pcbios_int_10h_83h(); break;
17224: case 0x8b: break;
17225: case 0x8c: m_CF = 1; break; // unknown
17226: case 0x8d: m_CF = 1; break; // unknown
17227: case 0x8e: m_CF = 1; break; // unknown
17228: case 0x90: pcbios_int_10h_90h(); break;
17229: case 0x91: pcbios_int_10h_91h(); break;
17230: case 0x92: break;
17231: case 0x93: break;
17232: case 0xef: pcbios_int_10h_efh(); break;
17233: case 0xfa: break; // ega register interface library is not installed
17234: case 0xfe: pcbios_int_10h_feh(); break;
17235: case 0xff: pcbios_int_10h_ffh(); break;
17236: default:
17237: 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));
17238: m_CF = 1;
17239: break;
17240: }
17241: break;
17242: case 0x11:
17243: // PC BIOS - Get Equipment List
17244: REG16(AX) = msdos_get_equipment();
17245: break;
17246: case 0x12:
17247: // PC BIOS - Get Memory Size
17248: REG16(AX) = *(UINT16 *)(mem + 0x413);
17249: break;
17250: case 0x13:
17251: // PC BIOS - Disk I/O
17252: {
17253: static UINT8 last = 0x00;
17254: switch(REG8(AH)) {
17255: case 0x00: pcbios_int_13h_00h(); break;
17256: case 0x01: // get last status
17257: REG8(AH) = last;
17258: break;
17259: case 0x02: pcbios_int_13h_02h(); break;
17260: case 0x03: pcbios_int_13h_03h(); break;
17261: case 0x04: pcbios_int_13h_04h(); break;
17262: case 0x08: pcbios_int_13h_08h(); break;
17263: case 0x0a: pcbios_int_13h_02h(); break;
17264: case 0x0b: pcbios_int_13h_03h(); break;
17265: case 0x0d: pcbios_int_13h_00h(); break;
17266: case 0x10: pcbios_int_13h_10h(); break;
17267: case 0x15: pcbios_int_13h_15h(); break;
17268: case 0x41: pcbios_int_13h_41h(); break;
17269: case 0x05: // format
17270: case 0x06:
17271: case 0x07:
17272: REG8(AH) = 0x0c; // unsupported track or invalid media
17273: m_CF = 1;
17274: break;
17275: case 0x09:
17276: case 0x0c: // seek
17277: case 0x11: // recalib
17278: case 0x14:
17279: case 0x17:
17280: REG8(AH) = 0x00; // successful completion
17281: break;
17282: case 0x21: // QUICKCACHE II v4.20 - Flush Cache
17283: case 0xa1: // Super PC-Kwik v3.20+ - Flush Cache
17284: REG8(AH) = 0x01; // invalid function
17285: m_CF = 1;
17286: break;
17287: default:
17288: unimplemented_13h("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));
17289: REG8(AH) = 0x01; // invalid function
17290: m_CF = 1;
17291: break;
17292: }
17293: last = REG8(AH);
17294: }
17295: break;
17296: case 0x14:
17297: // PC BIOS - Serial I/O
17298: switch(REG8(AH)) {
17299: case 0x00: pcbios_int_14h_00h(); break;
17300: case 0x01: pcbios_int_14h_01h(); break;
17301: case 0x02: pcbios_int_14h_02h(); break;
17302: case 0x03: pcbios_int_14h_03h(); break;
17303: case 0x04: pcbios_int_14h_04h(); break;
17304: case 0x05: pcbios_int_14h_05h(); break;
17305: default:
17306: 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));
17307: break;
17308: }
17309: break;
17310: case 0x15:
17311: // PC BIOS
17312: m_CF = 0;
17313: switch(REG8(AH)) {
17314: case 0x23: pcbios_int_15h_23h(); break;
17315: case 0x24: pcbios_int_15h_24h(); break;
17316: case 0x41: break;
17317: case 0x49: pcbios_int_15h_49h(); break;
17318: case 0x4f: m_CF = 1; break; // from DOSBox
17319: case 0x50: pcbios_int_15h_50h(); break;
17320: case 0x53: pcbios_int_15h_53h(); break;
17321: case 0x84: pcbios_int_15h_84h(); break;
17322: case 0x86: pcbios_int_15h_86h(); break;
17323: case 0x87: pcbios_int_15h_87h(); break;
17324: case 0x88: pcbios_int_15h_88h(); break;
17325: case 0x89: pcbios_int_15h_89h(); break;
17326: case 0x8a: pcbios_int_15h_8ah(); break;
17327: case 0x90: REG8(AH) = 0x00; break; // from DOSBox
17328: case 0x91: REG8(AH) = 0x00; break; // from DOSBox
17329: case 0xc0: // PS/2 ???
17330: #ifndef EXT_BIOS_TOP
17331: case 0xc1:
17332: #endif
17333: case 0xc3: // PS50+ ???
17334: case 0xc4:
17335: REG8(AH) = 0x86;
17336: m_CF = 1;
17337: break;
17338: #ifdef EXT_BIOS_TOP
17339: case 0xc1: pcbios_int_15h_c1h(); break;
17340: #endif
17341: case 0xc2: pcbios_int_15h_c2h(); break;
17342: #if defined(HAS_I386)
17343: case 0xc9: pcbios_int_15h_c9h(); break;
17344: #endif
17345: case 0xca: pcbios_int_15h_cah(); break;
17346: case 0xe8: pcbios_int_15h_e8h(); break;
17347: default:
17348: 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));
17349: REG8(AH) = 0x86;
17350: m_CF = 1;
17351: break;
17352: }
17353: break;
17354: case 0x16:
17355: // PC BIOS - Keyboard
17356: m_CF = 0;
17357: switch(REG8(AH)) {
17358: case 0x00: pcbios_int_16h_00h(); break;
17359: case 0x01: pcbios_int_16h_01h(); break;
17360: case 0x02: pcbios_int_16h_02h(); break;
17361: case 0x03: pcbios_int_16h_03h(); break;
17362: case 0x05: pcbios_int_16h_05h(); break;
17363: case 0x09: pcbios_int_16h_09h(); break;
17364: case 0x0a: pcbios_int_16h_0ah(); break;
17365: case 0x10: pcbios_int_16h_00h(); break;
17366: case 0x11: pcbios_int_16h_11h(); break;
17367: case 0x12: pcbios_int_16h_12h(); break;
17368: case 0x13: pcbios_int_16h_13h(); break;
17369: case 0x14: pcbios_int_16h_14h(); break;
17370: case 0x55: pcbios_int_16h_55h(); break;
17371: case 0x6f: pcbios_int_16h_6fh(); break;
17372: case 0xda: break; // unknown
17373: case 0xdb: break; // unknown
17374: case 0xff: break; // unknown
17375: default:
17376: 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));
17377: break;
17378: }
17379: break;
17380: case 0x17:
17381: // PC BIOS - Printer
17382: m_CF = 0;
17383: switch(REG8(AH)) {
17384: case 0x00: pcbios_int_17h_00h(); break;
17385: case 0x01: pcbios_int_17h_01h(); break;
17386: case 0x02: pcbios_int_17h_02h(); break;
17387: case 0x03: pcbios_int_17h_03h(); break;
17388: case 0x50: pcbios_int_17h_50h(); break;
17389: case 0x51: pcbios_int_17h_51h(); break;
17390: case 0x52: pcbios_int_17h_52h(); break;
17391: case 0x84: pcbios_int_17h_84h(); break;
17392: case 0x85: pcbios_int_17h_85h(); break;
17393: default:
17394: unimplemented_17h("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));
17395: break;
17396: }
17397: break;
17398: case 0x1a:
17399: // PC BIOS - Timer
17400: m_CF = 0;
17401: switch(REG8(AH)) {
17402: case 0x00: pcbios_int_1ah_00h(); break;
17403: case 0x01: break;
17404: case 0x02: pcbios_int_1ah_02h(); break;
17405: case 0x03: break;
17406: case 0x04: pcbios_int_1ah_04h(); break;
17407: case 0x05: break;
17408: case 0x0a: pcbios_int_1ah_0ah(); break;
17409: case 0x0b: break;
17410: case 0x35: break; // Word Perfect Third Party Interface?
17411: case 0x36: break; // Word Perfect Third Party Interface
17412: case 0x70: break; // SNAP? (Simple Network Application Protocol)
17413: case 0xb0: break; // Microsoft Real-Time Compression Interface (MRCI)
17414: case 0xb1: break; // PCI BIOS v2.0c+
17415: case 0xb4: break; // Intel Plug-and-Play Auto-Configuration
17416: default:
17417: 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));
17418: break;
17419: }
17420: break;
17421: case 0x1b:
17422: mem[0x471] = 0x00;
17423: break;
17424: case 0x20:
17425: try {
17426: msdos_process_terminate(SREG(CS), retval, 1);
17427: } catch(...) {
17428: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
17429: }
17430: break;
17431: case 0x30:
17432: // dummy interrupt for case map routine pointed in the country info
17433: // if(!(REG8(CL) >= 0x00 && REG8(CL) <= 0x24)) {
17434: // REG8(AL) = 0x00;
17435: // break;
17436: // }
17437: case 0x21:
17438: // MS-DOS System Call
17439: m_CF = 0;
17440: try {
17441: switch(num == 0x21 ? REG8(AH) : REG8(CL)) {
17442: case 0x00: msdos_int_21h_00h(); break;
17443: case 0x01: msdos_int_21h_01h(); break;
17444: case 0x02: msdos_int_21h_02h(); break;
17445: case 0x03: msdos_int_21h_03h(); break;
17446: case 0x04: msdos_int_21h_04h(); break;
17447: case 0x05: msdos_int_21h_05h(); break;
17448: case 0x06: msdos_int_21h_06h(); break;
17449: case 0x07: msdos_int_21h_07h(); break;
17450: case 0x08: msdos_int_21h_08h(); break;
17451: case 0x09: msdos_int_21h_09h(); break;
17452: case 0x0a: msdos_int_21h_0ah(); break;
17453: case 0x0b: msdos_int_21h_0bh(); break;
17454: case 0x0c: msdos_int_21h_0ch(); break;
17455: case 0x0d: msdos_int_21h_0dh(); break;
17456: case 0x0e: msdos_int_21h_0eh(); break;
17457: case 0x0f: msdos_int_21h_0fh(); break;
17458: case 0x10: msdos_int_21h_10h(); break;
17459: case 0x11: msdos_int_21h_11h(); break;
17460: case 0x12: msdos_int_21h_12h(); break;
17461: case 0x13: msdos_int_21h_13h(); break;
17462: case 0x14: msdos_int_21h_14h(); break;
17463: case 0x15: msdos_int_21h_15h(); break;
17464: case 0x16: msdos_int_21h_16h(); break;
17465: case 0x17: msdos_int_21h_17h(); break;
17466: case 0x18: msdos_int_21h_18h(); break;
17467: case 0x19: msdos_int_21h_19h(); break;
17468: case 0x1a: msdos_int_21h_1ah(); break;
17469: case 0x1b: msdos_int_21h_1bh(); break;
17470: case 0x1c: msdos_int_21h_1ch(); break;
17471: case 0x1d: msdos_int_21h_1dh(); break;
17472: case 0x1e: msdos_int_21h_1eh(); break;
17473: case 0x1f: msdos_int_21h_1fh(); break;
17474: case 0x20: msdos_int_21h_20h(); break;
17475: case 0x21: msdos_int_21h_21h(); break;
17476: case 0x22: msdos_int_21h_22h(); break;
17477: case 0x23: msdos_int_21h_23h(); break;
17478: case 0x24: msdos_int_21h_24h(); break;
17479: case 0x25: msdos_int_21h_25h(); break;
17480: case 0x26: msdos_int_21h_26h(); break;
17481: case 0x27: msdos_int_21h_27h(); break;
17482: case 0x28: msdos_int_21h_28h(); break;
17483: case 0x29: msdos_int_21h_29h(); break;
17484: case 0x2a: msdos_int_21h_2ah(); break;
17485: case 0x2b: msdos_int_21h_2bh(); break;
17486: case 0x2c: msdos_int_21h_2ch(); break;
17487: case 0x2d: msdos_int_21h_2dh(); break;
17488: case 0x2e: msdos_int_21h_2eh(); break;
17489: case 0x2f: msdos_int_21h_2fh(); break;
17490: case 0x30: msdos_int_21h_30h(); break;
17491: case 0x31: msdos_int_21h_31h(); break;
17492: case 0x32: msdos_int_21h_32h(); break;
17493: case 0x33: msdos_int_21h_33h(); break;
17494: case 0x34: msdos_int_21h_34h(); break;
17495: case 0x35: msdos_int_21h_35h(); break;
17496: case 0x36: msdos_int_21h_36h(); break;
17497: case 0x37: msdos_int_21h_37h(); break;
17498: case 0x38: msdos_int_21h_38h(); break;
17499: case 0x39: msdos_int_21h_39h(0); break;
17500: case 0x3a: msdos_int_21h_3ah(0); break;
17501: case 0x3b: msdos_int_21h_3bh(0); break;
17502: case 0x3c: msdos_int_21h_3ch(); break;
17503: case 0x3d: msdos_int_21h_3dh(); break;
17504: case 0x3e: msdos_int_21h_3eh(); break;
17505: case 0x3f: msdos_int_21h_3fh(); break;
17506: case 0x40: msdos_int_21h_40h(); break;
17507: case 0x41: msdos_int_21h_41h(0); break;
17508: case 0x42: msdos_int_21h_42h(); break;
17509: case 0x43: msdos_int_21h_43h(0); break;
17510: case 0x44: msdos_int_21h_44h(); break;
17511: case 0x45: msdos_int_21h_45h(); break;
17512: case 0x46: msdos_int_21h_46h(); break;
17513: case 0x47: msdos_int_21h_47h(0); break;
17514: case 0x48: msdos_int_21h_48h(); break;
17515: case 0x49: msdos_int_21h_49h(); break;
17516: case 0x4a: msdos_int_21h_4ah(); break;
17517: case 0x4b: msdos_int_21h_4bh(); break;
17518: case 0x4c: msdos_int_21h_4ch(); break;
17519: case 0x4d: msdos_int_21h_4dh(); break;
17520: case 0x4e: msdos_int_21h_4eh(); break;
17521: case 0x4f: msdos_int_21h_4fh(); break;
17522: case 0x50: msdos_int_21h_50h(); break;
17523: case 0x51: msdos_int_21h_51h(); break;
17524: case 0x52: msdos_int_21h_52h(); break;
17525: case 0x53: msdos_int_21h_53h(); break;
17526: case 0x54: msdos_int_21h_54h(); break;
17527: case 0x55: msdos_int_21h_55h(); break;
17528: case 0x56: msdos_int_21h_56h(0); break;
17529: case 0x57: msdos_int_21h_57h(); break;
17530: case 0x58: msdos_int_21h_58h(); break;
17531: case 0x59: msdos_int_21h_59h(); break;
17532: case 0x5a: msdos_int_21h_5ah(); break;
17533: case 0x5b: msdos_int_21h_5bh(); break;
17534: case 0x5c: msdos_int_21h_5ch(); break;
17535: case 0x5d: msdos_int_21h_5dh(); break;
17536: case 0x5e: msdos_int_21h_5eh(); break;
17537: case 0x5f: msdos_int_21h_5fh(); break;
17538: case 0x60: msdos_int_21h_60h(0); break;
17539: case 0x61: msdos_int_21h_61h(); break;
17540: case 0x62: msdos_int_21h_62h(); break;
17541: case 0x63: msdos_int_21h_63h(); break;
17542: // 0x64: Set Device Driver Lockahead Flag
17543: case 0x65: msdos_int_21h_65h(); break;
17544: case 0x66: msdos_int_21h_66h(); break;
17545: case 0x67: msdos_int_21h_67h(); break;
17546: case 0x68: msdos_int_21h_68h(); break;
17547: case 0x69: msdos_int_21h_69h(); break;
17548: case 0x6a: msdos_int_21h_6ah(); break;
17549: case 0x6b: msdos_int_21h_6bh(); break;
17550: case 0x6c: msdos_int_21h_6ch(0); break;
17551: case 0x6d: // Find First ROM Program
17552: case 0x6e: // Find Next ROM Program
17553: case 0x6f: // Get/Set ROM Scan Start Address
17554: REG8(AL) = 0x00; // if not supported (DOS <5, MS-DOS 5+ non-ROM versions)
17555: break;
17556: case 0x70: msdos_int_21h_70h(); break;
17557: case 0x71: // Windows95 - Long Filename Functions
17558: switch(REG8(AL)) {
17559: case 0x0d: msdos_int_21h_710dh(); break;
17560: case 0x39: msdos_int_21h_39h(1); break;
17561: case 0x3a: msdos_int_21h_3ah(1); break;
17562: case 0x3b: msdos_int_21h_3bh(1); break;
17563: case 0x41: msdos_int_21h_7141h(); break;
17564: case 0x43: msdos_int_21h_43h(1); break;
17565: case 0x47: msdos_int_21h_47h(1); break;
17566: case 0x4e: msdos_int_21h_714eh(); break;
17567: case 0x4f: msdos_int_21h_714fh(); break;
17568: case 0x56: msdos_int_21h_56h(1); break;
17569: case 0x60: msdos_int_21h_60h(1); break;
17570: case 0x6c: msdos_int_21h_6ch(1); break;
17571: case 0xa0: msdos_int_21h_71a0h(); break;
17572: case 0xa1: msdos_int_21h_71a1h(); break;
17573: case 0xa6: msdos_int_21h_71a6h(); break;
17574: case 0xa7: msdos_int_21h_71a7h(); break;
17575: case 0xa8: msdos_int_21h_71a8h(); break;
17576: case 0xa9: msdos_int_21h_6ch(1); break;
17577: case 0xaa: msdos_int_21h_71aah(); break;
17578: default:
17579: 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));
17580: REG16(AX) = 0x7100;
17581: m_CF = 1;
17582: break;
17583: }
17584: break;
17585: case 0x72: // Windows95 beta - LFN FindClose
17586: // 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));
17587: REG16(AX) = 0x7200;
17588: m_CF = 1;
17589: break;
17590: case 0x73: // Windows95 - FAT32 Functions
17591: switch(REG8(AL)) {
17592: case 0x00: msdos_int_21h_7300h(); break;
17593: // 0x01: Set Drive Locking ???
17594: case 0x02: msdos_int_21h_7302h(); break;
17595: case 0x03: msdos_int_21h_7303h(); break;
17596: // 0x04: Set DPB to Use for Formatting
17597: // 0x05: Extended Absolute Disk Read/Write
17598: default:
17599: 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));
17600: REG16(AX) = 0x7300;
17601: m_CF = 1;
17602: break;
17603: }
17604: break;
17605: case 0xdb: msdos_int_21h_dbh(); break;
17606: case 0xdc: msdos_int_21h_dch(); break;
17607: default:
17608: 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));
17609: REG16(AX) = 0x01;
17610: m_CF = 1;
17611: break;
17612: }
17613: } catch(int error) {
17614: REG16(AX) = error;
17615: m_CF = 1;
17616: } catch(...) {
17617: REG16(AX) = 0x1f; // general failure
17618: m_CF = 1;
17619: }
17620: if(m_CF) {
17621: sda_t *sda = (sda_t *)(mem + SDA_TOP);
17622: sda->int21h_5d0ah_called = 0;
17623: sda->extended_error_code = REG16(AX);
17624: switch(sda->extended_error_code) {
17625: case 4: // Too many open files
17626: case 8: // Insufficient memory
17627: sda->error_class = 1; // Out of resource
17628: break;
17629: case 5: // Access denied
17630: sda->error_class = 3; // Authorization
17631: break;
17632: case 7: // Memory control block destroyed
17633: sda->error_class = 4; // Internal
17634: break;
17635: case 2: // File not found
17636: case 3: // Path not found
17637: case 15: // Invaid drive specified
17638: case 18: // No more files
17639: sda->error_class = 8; // Not found
17640: break;
17641: case 32: // Sharing violation
17642: case 33: // Lock violation
17643: sda->error_class = 10; // Locked
17644: break;
17645: // case 16: // Removal of current directory attempted
17646: case 19: // Attempted write on protected disk
17647: case 21: // Drive not ready
17648: // case 29: // Write failure
17649: // case 30: // Read failure
17650: // case 82: // Cannot create subdirectory
17651: sda->error_class = 11; // Media
17652: break;
17653: case 80: // File already exists
17654: sda->error_class = 12; // Already exist
17655: break;
17656: default:
17657: sda->error_class = 13; // Unknown
17658: break;
17659: }
17660: sda->suggested_action = 1; // Retry
17661: sda->locus_of_last_error = 1; // Unknown
17662: }
17663: if(ctrl_break_checking && ctrl_break_detected) {
17664: // raise int 23h
17665: #if defined(HAS_I386)
17666: m_ext = 0; // not an external interrupt
17667: i386_trap(0x23, 1, 0);
17668: m_ext = 1;
17669: #else
17670: PREFIX86(_interrupt)(0x23);
17671: #endif
17672: }
17673: break;
17674: case 0x22:
17675: fatalerror("int 22h (terminate address)\n");
17676: case 0x23:
17677: try {
17678: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
17679: } catch(...) {
17680: fatalerror("failed to terminate the current process by int 23h\n");
17681: }
17682: break;
17683: case 0x24:
17684: /*
17685: try {
17686: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
17687: } catch(...) {
17688: fatalerror("failed to terminate the current process by int 24h\n");
17689: }
17690: */
17691: msdos_int_24h();
17692: break;
17693: case 0x25:
17694: msdos_int_25h();
17695: break;
17696: case 0x26:
17697: msdos_int_26h();
17698: break;
17699: case 0x27:
17700: try {
17701: msdos_int_27h();
17702: } catch(...) {
17703: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
17704: }
17705: break;
17706: case 0x28:
17707: Sleep(10);
17708: REQUEST_HARDWRE_UPDATE();
17709: break;
17710: case 0x29:
17711: msdos_int_29h();
17712: break;
17713: case 0x2e:
17714: msdos_int_2eh();
17715: break;
17716: case 0x2f:
17717: // multiplex interrupt
17718: switch(REG8(AH)) {
17719: case 0x05: msdos_int_2fh_05h(); break;
17720: case 0x06: msdos_int_2fh_06h(); break;
17721: case 0x11: msdos_int_2fh_11h(); break;
17722: case 0x12: msdos_int_2fh_12h(); break;
17723: case 0x13: msdos_int_2fh_13h(); break;
17724: case 0x14: msdos_int_2fh_14h(); break;
17725: case 0x15: msdos_int_2fh_15h(); break;
17726: case 0x16: msdos_int_2fh_16h(); break;
17727: case 0x19: msdos_int_2fh_19h(); break;
17728: case 0x1a: msdos_int_2fh_1ah(); break;
17729: case 0x40: msdos_int_2fh_40h(); break;
17730: case 0x43: msdos_int_2fh_43h(); break;
17731: case 0x46: msdos_int_2fh_46h(); break;
17732: case 0x48: msdos_int_2fh_48h(); break;
17733: case 0x4a: msdos_int_2fh_4ah(); break;
17734: case 0x4b: msdos_int_2fh_4bh(); break;
17735: case 0x4d: msdos_int_2fh_4dh(); break;
17736: case 0x4f: msdos_int_2fh_4fh(); break;
17737: case 0x55: msdos_int_2fh_55h(); break;
17738: case 0x56: msdos_int_2fh_56h(); break;
17739: case 0xad: msdos_int_2fh_adh(); break;
17740: case 0xae: msdos_int_2fh_aeh(); break;
17741: case 0xb7: msdos_int_2fh_b7h(); break;
17742: default:
17743: switch(REG8(AL)) {
17744: case 0x00:
17745: // This is not installed
17746: // REG8(AL) = 0x00;
17747: break;
17748: case 0x01:
17749: // Quarterdeck RPCI - QEMM/QRAM - PCL-838.EXE is not installed
17750: if(REG8(AH) == 0xd2 && REG16(BX) == 0x5145 && REG16(CX) == 0x4d4d && REG16(DX) == 0x3432) {
17751: break;
17752: }
17753: // Banyan VINES v4+ is not installed
17754: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
17755: break;
17756: }
17757: // Quarterdeck QDPMI.SYS v1.0 is not installed
17758: if(REG8(AH) == 0xde && REG16(BX) == 0x4450 && REG16(CX) == 0x4d49 && REG16(DX) == 0x8f4f) {
17759: break;
17760: }
17761: default:
17762: // NORTON UTILITIES 5.0+
17763: if(REG8(AH) == 0xfe && REG16(DI) == 0x4e55) {
17764: break;
17765: }
17766: 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));
17767: REG16(AX) = 0x01; // invalid function
17768: m_CF = 1;
17769: break;
17770: }
17771: break;
17772: }
17773: break;
17774: case 0x33:
17775: switch(REG8(AH)) {
17776: case 0x00:
17777: // Mouse
17778: switch(REG16(AX)) {
17779: case 0x0000: msdos_int_33h_0000h(); break;
17780: case 0x0001: msdos_int_33h_0001h(); break;
17781: case 0x0002: msdos_int_33h_0002h(); break;
17782: case 0x0003: msdos_int_33h_0003h(); break;
17783: case 0x0004: msdos_int_33h_0004h(); break;
17784: case 0x0005: msdos_int_33h_0005h(); break;
17785: case 0x0006: msdos_int_33h_0006h(); break;
17786: case 0x0007: msdos_int_33h_0007h(); break;
17787: case 0x0008: msdos_int_33h_0008h(); break;
17788: case 0x0009: msdos_int_33h_0009h(); break;
17789: case 0x000a: msdos_int_33h_000ah(); break;
17790: case 0x000b: msdos_int_33h_000bh(); break;
17791: case 0x000c: msdos_int_33h_000ch(); break;
17792: case 0x000d: break; // MS MOUSE v1.0+ - Light Pen Emulation On
17793: case 0x000e: break; // MS MOUSE v1.0+ - Light Pen Emulation Off
17794: case 0x000f: msdos_int_33h_000fh(); break;
17795: case 0x0010: break; // MS MOUSE v1.0+ - Define Screen Region for Updating
17796: case 0x0011: msdos_int_33h_0011h(); break;
17797: case 0x0012: REG16(AX) = 0xffff; break; // MS MOUSE - Set Large Graphics Cursor Block
17798: case 0x0013: break; // MS MOUSE v5.0+ - Define Double-Speed Threshold
17799: case 0x0014: msdos_int_33h_0014h(); break;
17800: case 0x0015: msdos_int_33h_0015h(); break;
17801: case 0x0016: msdos_int_33h_0016h(); break;
17802: case 0x0017: msdos_int_33h_0017h(); break;
17803: case 0x0018: msdos_int_33h_0018h(); break;
17804: case 0x0019: msdos_int_33h_0019h(); break;
17805: case 0x001a: msdos_int_33h_001ah(); break;
17806: case 0x001b: msdos_int_33h_001bh(); break;
17807: case 0x001c: break; // MS MOUSE v6.0+ - Set Interrupt Rate
17808: case 0x001d: msdos_int_33h_001dh(); break;
17809: case 0x001e: msdos_int_33h_001eh(); break;
17810: case 0x001f: msdos_int_33h_001fh(); break;
17811: case 0x0020: msdos_int_33h_0020h(); break;
17812: case 0x0021: msdos_int_33h_0021h(); break;
17813: case 0x0022: msdos_int_33h_0022h(); break;
17814: case 0x0023: msdos_int_33h_0023h(); break;
17815: case 0x0024: msdos_int_33h_0024h(); break;
17816: case 0x0025: msdos_int_33h_0025h(); break;
17817: case 0x0026: msdos_int_33h_0026h(); break;
17818: case 0x0027: msdos_int_33h_0027h(); break;
17819: case 0x0028: msdos_int_33h_0028h(); break;
17820: case 0x0029: msdos_int_33h_0029h(); break;
17821: case 0x002a: msdos_int_33h_002ah(); break;
17822: // 0x002b: MS MOUSE v7.0+ - Load Acceleration Profiles
17823: // 0x002c: MS MOUSE v7.0+ - Get Acceleration Profiles
17824: // 0x002d: MS MOUSE v7.0+ - Select Acceleration Profile
17825: // 0x002e: MS MOUSE v8.10+ - Set Acceleration Profile Names
17826: case 0x002f: break; // Mouse Hardware Reset
17827: // 0x0030: MS MOUSE v7.04+ - Get/Set BallPoint Information
17828: case 0x0031: msdos_int_33h_0031h(); break;
17829: case 0x0032: msdos_int_33h_0032h(); break;
17830: // 0x0033: MS MOUSE v7.05+ - Get Switch Settings And Acceleration Profile Data
17831: // 0x0034: MS MOUSE v8.0+ - Get Initialization File
17832: // 0x0035: MS MOUSE v8.10+ - LCD Screen Large Pointer Support
17833: case 0x004d: msdos_int_33h_004dh(); break;
17834: case 0x006d: msdos_int_33h_006dh(); break;
17835: default:
17836: 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));
17837: break;
17838: }
17839: break;
17840: default:
17841: 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));
17842: break;
17843: }
17844: break;
17845: case 0x65:
17846: // dummy interrupt for EMS (int 67h)
17847: switch(REG8(AH)) {
17848: case 0x40: msdos_int_67h_40h(); break;
17849: case 0x41: msdos_int_67h_41h(); break;
17850: case 0x42: msdos_int_67h_42h(); break;
17851: case 0x43: msdos_int_67h_43h(); break;
17852: case 0x44: msdos_int_67h_44h(); break;
17853: case 0x45: msdos_int_67h_45h(); break;
17854: case 0x46: msdos_int_67h_46h(); break;
17855: case 0x47: msdos_int_67h_47h(); break;
17856: case 0x48: msdos_int_67h_48h(); break;
17857: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
17858: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
17859: case 0x4b: msdos_int_67h_4bh(); break;
17860: case 0x4c: msdos_int_67h_4ch(); break;
17861: case 0x4d: msdos_int_67h_4dh(); break;
17862: case 0x4e: msdos_int_67h_4eh(); break;
17863: case 0x4f: msdos_int_67h_4fh(); break;
17864: case 0x50: msdos_int_67h_50h(); break;
17865: case 0x51: msdos_int_67h_51h(); break;
17866: case 0x52: msdos_int_67h_52h(); break;
17867: case 0x53: msdos_int_67h_53h(); break;
17868: case 0x54: msdos_int_67h_54h(); break;
17869: case 0x55: msdos_int_67h_55h(); break;
17870: case 0x56: msdos_int_67h_56h(); break;
17871: case 0x57: msdos_int_67h_57h(); break;
17872: case 0x58: msdos_int_67h_58h(); break;
17873: case 0x59: msdos_int_67h_59h(); break;
17874: case 0x5a: msdos_int_67h_5ah(); break;
17875: case 0x5b: msdos_int_67h_5bh(); break;
17876: // 0x5c: LIM EMS 4.0 - Prepare Expanded Memory Hardware For Warm Boot
17877: case 0x5d: msdos_int_67h_5dh(); break;
17878: case 0x70: msdos_int_67h_70h(); break;
17879: // 0xde: VCPI
17880: case 0xde: msdos_int_67h_deh(); break;
17881: default:
17882: 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));
17883: REG8(AH) = 0x84;
17884: break;
17885: }
17886: break;
17887: #ifdef SUPPORT_XMS
17888: case 0x66:
17889: // dummy interrupt for XMS (call far)
17890: try {
17891: switch(REG8(AH)) {
17892: case 0x00: msdos_call_xms_00h(); break;
17893: case 0x01: msdos_call_xms_01h(); break;
17894: case 0x02: msdos_call_xms_02h(); break;
17895: case 0x03: msdos_call_xms_03h(); break;
17896: case 0x04: msdos_call_xms_04h(); break;
17897: case 0x05: msdos_call_xms_05h(); break;
17898: case 0x06: msdos_call_xms_06h(); break;
17899: case 0x07: msdos_call_xms_07h(); break;
17900: case 0x08: msdos_call_xms_08h(); break;
17901: case 0x09: msdos_call_xms_09h(); break;
17902: case 0x0a: msdos_call_xms_0ah(); break;
17903: case 0x0b: msdos_call_xms_0bh(); break;
17904: case 0x0c: msdos_call_xms_0ch(); break;
17905: case 0x0d: msdos_call_xms_0dh(); break;
17906: case 0x0e: msdos_call_xms_0eh(); break;
17907: case 0x0f: msdos_call_xms_0fh(); break;
17908: case 0x10: msdos_call_xms_10h(); break;
17909: case 0x11: msdos_call_xms_11h(); break;
17910: case 0x12: msdos_call_xms_12h(); break;
17911: #if defined(HAS_I386)
17912: case 0x88: msdos_call_xms_88h(); break;
17913: case 0x89: msdos_call_xms_89h(); break;
17914: case 0x8e: msdos_call_xms_8eh(); break;
17915: case 0x8f: msdos_call_xms_8fh(); break;
17916: #endif
17917: default:
17918: 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));
17919: REG16(AX) = 0x0000;
17920: REG8(BL) = 0x80; // function not implemented
17921: break;
17922: }
17923: } catch(...) {
17924: REG16(AX) = 0x0000;
17925: REG8(BL) = 0x8f; // unrecoverable driver error
17926: }
17927: break;
17928: #endif
17929: /*
17930: case 0x67:
17931: // int 67h handler is in EMS device driver (EMMXXXX0) and it calls int 65h
17932: // NOTE: some softwares get address of int 67h handler and recognize the address is in EMS device driver
17933: break;
17934: */
17935: case 0x69:
17936: // irq12 (mouse)
17937: mouse_push_ax = REG16(AX);
17938: mouse_push_bx = REG16(BX);
17939: mouse_push_cx = REG16(CX);
17940: mouse_push_dx = REG16(DX);
17941: mouse_push_si = REG16(SI);
17942: mouse_push_di = REG16(DI);
17943:
17944: if(mouse.status_irq && mouse.call_addr.dw) {
17945: REG16(AX) = mouse.status_irq;
17946: REG16(BX) = mouse.get_buttons();
17947: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
17948: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
17949: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
17950: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
17951:
17952: mem[DUMMY_TOP + 0x02] = 0x9a; // call far
17953: mem[DUMMY_TOP + 0x03] = mouse.call_addr.w.l & 0xff;
17954: mem[DUMMY_TOP + 0x04] = mouse.call_addr.w.l >> 8;
17955: mem[DUMMY_TOP + 0x05] = mouse.call_addr.w.h & 0xff;
17956: mem[DUMMY_TOP + 0x06] = mouse.call_addr.w.h >> 8;
17957: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy)
17958: mem[DUMMY_TOP + 0x08] = 0x6b;
17959: break;
17960: }
17961: for(int i = 0; i < 8; i++) {
17962: if((mouse.status_irq_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
17963: REG16(AX) = mouse.status_irq_alt;
17964: REG16(BX) = mouse.get_buttons();
17965: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
17966: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
17967: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
17968: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
17969:
17970: mem[DUMMY_TOP + 0x02] = 0x9a; // call far
17971: mem[DUMMY_TOP + 0x03] = mouse.call_addr_alt[i].w.l & 0xff;
17972: mem[DUMMY_TOP + 0x04] = mouse.call_addr_alt[i].w.l >> 8;
17973: mem[DUMMY_TOP + 0x05] = mouse.call_addr_alt[i].w.h & 0xff;
17974: mem[DUMMY_TOP + 0x06] = mouse.call_addr_alt[i].w.h >> 8;
17975: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy)
17976: mem[DUMMY_TOP + 0x08] = 0x6b;
17977: break;
17978: }
17979: }
17980: if(mouse.status_irq_ps2 && mouse.call_addr_ps2.dw && mouse.enabled_ps2) {
17981: UINT16 data_1st, data_2nd, data_3rd;
17982: pcbios_read_from_ps2_mouse(&data_1st, &data_2nd, &data_3rd);
17983: i386_push16(data_1st);
17984: i386_push16(data_2nd);
17985: i386_push16(data_3rd);
17986: i386_push16(0x0000);
17987:
17988: mem[DUMMY_TOP + 0x02] = 0x9a; // call far
17989: mem[DUMMY_TOP + 0x03] = mouse.call_addr_ps2.w.l & 0xff;
17990: mem[DUMMY_TOP + 0x04] = mouse.call_addr_ps2.w.l >> 8;
17991: mem[DUMMY_TOP + 0x05] = mouse.call_addr_ps2.w.h & 0xff;
17992: mem[DUMMY_TOP + 0x06] = mouse.call_addr_ps2.w.h >> 8;
17993: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6ah (dummy)
17994: mem[DUMMY_TOP + 0x08] = 0x6a;
17995: break;
17996: }
17997: // invalid call addr :-(
17998: mem[DUMMY_TOP + 0x02] = 0x90; // nop
17999: mem[DUMMY_TOP + 0x03] = 0x90; // nop
18000: mem[DUMMY_TOP + 0x04] = 0x90; // nop
18001: mem[DUMMY_TOP + 0x05] = 0x90; // nop
18002: mem[DUMMY_TOP + 0x06] = 0x90; // nop
18003: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy)
18004: mem[DUMMY_TOP + 0x08] = 0x6b;
18005: break;
18006: case 0x6a:
18007: // end of ps/2 mouse bios
18008: i386_pop16();
18009: i386_pop16();
18010: i386_pop16();
18011: i386_pop16();
18012: case 0x6b:
18013: // end of irq12 (mouse)
18014: REG16(AX) = mouse_push_ax;
18015: REG16(BX) = mouse_push_bx;
18016: REG16(CX) = mouse_push_cx;
18017: REG16(DX) = mouse_push_dx;
18018: REG16(SI) = mouse_push_si;
18019: REG16(DI) = mouse_push_di;
18020:
18021: // EOI
18022: if((pic[1].isr &= ~(1 << 4)) == 0) {
18023: pic[0].isr &= ~(1 << 2); // master
18024: }
18025: pic_update();
18026: break;
18027: case 0x6c:
18028: // dummy interrupt for case map routine pointed in the country info
18029: if(REG8(AL) >= 0x80) {
18030: char tmp[2] = {0};
18031: tmp[0] = REG8(AL);
18032: my_strupr(tmp);
18033: REG8(AL) = tmp[0];
18034: }
18035: break;
18036: case 0x6d:
18037: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
18038: REG8(AL) = 0x86; // not supported
18039: m_CF = 1;
18040: break;
18041: case 0x6e:
18042: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
18043: {
18044: UINT16 code = REG16(AX);
18045: if(code & 0xf0) {
18046: code = (code & 7) | ((code & 0x10) >> 1);
18047: }
18048: for(int i = 0; i < array_length(param_error_table); i++) {
18049: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
18050: const char *message = NULL;
18051: if(active_code_page == 932) {
18052: message = param_error_table[i].message_japanese;
18053: }
18054: if(message == NULL) {
18055: message = param_error_table[i].message_english;
18056: }
18057: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
18058: strcpy((char *)(mem + WORK_TOP + 1), message);
18059:
18060: SREG(ES) = WORK_TOP >> 4;
18061: i386_load_segment_descriptor(ES);
18062: REG16(DI) = 0x0000;
18063: break;
18064: }
18065: }
18066: }
18067: break;
18068: case 0x6f:
18069: // dummy interrupt for end of alter page map and call
18070: {
18071: UINT16 handles[4], pages[4];
18072:
18073: // pop old mapping data in new mapping
18074: for(int i = 0; i < 4; i++) {
18075: pages [3 - i] = i386_pop16();
18076: handles[3 - i] = i386_pop16();
18077: }
18078:
18079: // restore old mapping
18080: for(int i = 0; i < 4; i++) {
18081: UINT16 handle = handles[i];
18082: UINT16 page = pages [i];
18083:
18084: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
18085: ems_map_page(i, handle, page);
18086: } else {
18087: ems_unmap_page(i);
18088: }
18089: }
18090: // do ret_far (pop cs/ip) in old mapping
18091: }
18092: break;
18093: case 0x70:
18094: case 0x71:
18095: case 0x72:
18096: case 0x73:
18097: case 0x74:
18098: case 0x75:
18099: case 0x76:
18100: case 0x77:
18101: // EOI
18102: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
18103: pic[0].isr &= ~(1 << 2); // master
18104: }
18105: pic_update();
18106: break;
18107: default:
18108: // 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));
18109: break;
18110: }
18111:
18112: // update cursor position
18113: if(cursor_moved) {
18114: pcbios_update_cursor_position();
18115: cursor_moved = false;
18116: }
18117: }
18118:
18119: // init
18120:
18121: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
18122: {
18123: // init file handler
18124: memset(file_handler, 0, sizeof(file_handler));
18125: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
18126: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
18127: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
18128: #ifdef MAP_AUX_DEVICE_TO_FILE
18129: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
18130: #else
18131: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
18132: #endif
18133: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
18134: }
18135: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
18136: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
18137: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1
18138: }
18139: _dup2(0, DUP_STDIN);
18140: _dup2(1, DUP_STDOUT);
18141: _dup2(2, DUP_STDERR);
18142: _dup2(3, DUP_STDAUX);
18143: _dup2(4, DUP_STDPRN);
18144:
18145: // init mouse
18146: memset(&mouse, 0, sizeof(mouse));
18147: mouse.enabled = true; // from DOSBox
18148: mouse.hidden = 1; // hidden in default ???
18149: mouse.old_hidden = 1; // from DOSBox
18150: mouse.max_position.x = 8 * (scr_width - 1);
18151: mouse.max_position.y = 8 * (scr_height - 1);
18152: mouse.mickey.x = 8;
18153: mouse.mickey.y = 16;
18154:
18155: #ifdef SUPPORT_XMS
18156: // init xms
18157: msdos_xms_init();
18158: #endif
18159:
18160: // init process
18161: memset(process, 0, sizeof(process));
18162:
18163: // init dtainfo
18164: msdos_dta_info_init();
18165:
18166: // init memory
18167: memset(mem, 0, sizeof(mem));
18168:
18169: // bios data area
18170: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
18171: CONSOLE_SCREEN_BUFFER_INFO csbi;
18172: GetConsoleScreenBufferInfo(hStdout, &csbi);
18173: // CONSOLE_FONT_INFO cfi;
18174: // GetCurrentConsoleFont(hStdout, FALSE, &cfi);
18175:
18176: int regen = min(scr_width * scr_height * 2, 0x8000);
18177: text_vram_top_address = TEXT_VRAM_TOP;
18178: text_vram_end_address = text_vram_top_address + regen;
18179: shadow_buffer_top_address = SHADOW_BUF_TOP;
18180: shadow_buffer_end_address = shadow_buffer_top_address + regen;
18181: cursor_position_address = 0x450 + mem[0x462] * 2;
18182:
18183: if(regen > 0x4000) {
18184: regen = 0x8000;
18185: vram_pages = 1;
18186: } else if(regen > 0x2000) {
18187: regen = 0x4000;
18188: vram_pages = 2;
18189: } else if(regen > 0x1000) {
18190: regen = 0x2000;
18191: vram_pages = 4;
18192: } else {
18193: regen = 0x1000;
18194: vram_pages = 8;
18195: }
18196:
18197: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
18198: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
18199: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
18200: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
18201: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
18202: *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
18203: *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
18204: #ifdef EXT_BIOS_TOP
18205: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
18206: #endif
18207: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
18208: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
18209: *(UINT16 *)(mem + 0x41a) = 0x1e;
18210: *(UINT16 *)(mem + 0x41c) = 0x1e;
18211: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
18212: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
18213: *(UINT16 *)(mem + 0x44c) = regen;
18214: *(UINT16 *)(mem + 0x44e) = 0;
18215: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
18216: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
18217: *(UINT8 *)(mem + 0x460) = 7;
18218: *(UINT8 *)(mem + 0x461) = 7;
18219: *(UINT8 *)(mem + 0x462) = 0;
18220: *(UINT16 *)(mem + 0x463) = 0x3d4;
18221: *(UINT8 *)(mem + 0x465) = 0x09;
18222: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
18223: *(UINT16 *)(mem + 0x472) = 0x4321; // preserve memory in cpu reset
18224: *(UINT16 *)(mem + 0x480) = 0x1e;
18225: *(UINT16 *)(mem + 0x482) = 0x3e;
18226: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
18227: *(UINT16 *)(mem + 0x485) = font_height;
18228: *(UINT8 *)(mem + 0x487) = 0x60;
18229: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
18230: #ifdef EXT_BIOS_TOP
18231: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
18232: #endif
18233:
18234: // initial screen
18235: SMALL_RECT rect;
18236: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
18237: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
18238: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
18239: for(int x = 0; x < scr_width; x++) {
18240: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
18241: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
18242: }
18243: }
18244:
18245: // init mcb
18246: int seg = MEMORY_TOP >> 4;
18247:
18248: // iret table
18249: // note: int 2eh vector should address the routine in command.com,
18250: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
18251: // so move iret table into allocated memory block
18252: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
18253: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, (IRET_SIZE + 5 * 128) >> 4);
18254: IRET_TOP = seg << 4;
18255: seg += (IRET_SIZE + 5 * 128) >> 4;
18256: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
18257:
18258: // note: SO1 checks int 21h vector and if it aims iret (cfh)
18259: // it is recognized SO1 is not running on MS-DOS environment
18260: for(int i = 0; i < 128; i++) {
18261: // jmp far (IRET_TOP >> 4):(interrupt number)
18262: *(UINT8 *)(mem + IRET_TOP + IRET_SIZE + 5 * i + 0) = 0xea;
18263: *(UINT16 *)(mem + IRET_TOP + IRET_SIZE + 5 * i + 1) = i;
18264: *(UINT16 *)(mem + IRET_TOP + IRET_SIZE + 5 * i + 3) = IRET_TOP >> 4;
18265: }
18266:
18267: // dummy xms/ems device
18268: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
18269: XMS_TOP = seg << 4;
18270: seg += XMS_SIZE >> 4;
18271:
18272: // environment
18273: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
18274: int env_seg = seg;
18275: int ofs = 0;
18276: char env_append[ENV_SIZE] = {0}, append_added = 0;
18277: char comspec_added = 0;
18278: char lastdrive_added = 0;
18279: char env_msdos_path[ENV_SIZE] = {0};
18280: char env_path[ENV_SIZE] = {0}, path_added = 0;
18281: char prompt_added = 0;
18282: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
18283: char tz_added = 0;
18284: const char *path, *short_path;
18285:
18286: if((path = getenv("MSDOS_APPEND")) != NULL) {
18287: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
18288: strcpy(env_append, short_path);
18289: }
18290: }
18291: if((path = getenv("APPEND")) != NULL) {
18292: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
18293: if(env_append[0] != '\0') {
18294: strcat(env_append, ";");
18295: }
18296: strcat(env_append, short_path);
18297: }
18298: }
18299:
18300: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
18301: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
18302: strcpy(comspec_path, short_path);
18303: }
18304: }
18305: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
18306: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
18307: strcpy(comspec_path, short_path);
18308: }
18309: }
18310:
18311: if((path = getenv("MSDOS_PATH")) != NULL) {
18312: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
18313: strcpy(env_msdos_path, short_path);
18314: strcpy(env_path, short_path);
18315: }
18316: }
18317: if((path = getenv("PATH")) != NULL) {
18318: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
18319: if(env_path[0] != '\0') {
18320: strcat(env_path, ";");
18321: }
18322: strcat(env_path, short_path);
18323: }
18324: }
18325:
18326: if(GetTempPathA(ENV_SIZE, env_temp) != 0) {
18327: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
18328: }
18329: for(int i = 0; i < 4; i++) {
18330: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
18331: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
18332: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
18333: strcpy(env_temp, short_path);
18334: break;
18335: }
18336: }
18337: }
18338:
18339: for(char **p = envp; p != NULL && *p != NULL; p++) {
18340: // lower to upper
18341: char tmp[ENV_SIZE], name[ENV_SIZE];
18342: strcpy(tmp, *p);
18343: for(int i = 0;; i++) {
18344: if(tmp[i] == '=') {
18345: tmp[i] = '\0';
18346: sprintf(name, ";%s;", tmp);
18347: my_strupr(name);
18348: tmp[i] = '=';
18349: break;
18350: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
18351: tmp[i] = (tmp[i] - 'a') + 'A';
18352: }
18353: }
18354: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
18355: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
18356: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
18357: // ignore non standard environments
18358: } else {
18359: if(strncmp(tmp, "APPEND=", 7) == 0) {
18360: if(env_append[0] != '\0') {
18361: sprintf(tmp, "APPEND=%s", env_append);
18362: } else {
18363: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
18364: }
18365: append_added = 1;
18366: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
18367: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
18368: comspec_added = 1;
18369: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
18370: char *env = getenv("MSDOS_LASTDRIVE");
18371: if(env != NULL) {
18372: sprintf(tmp, "LASTDRIVE=%s", env);
18373: }
18374: lastdrive_added = 1;
18375: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
18376: if(env_msdos_path[0] != '\0') {
18377: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
18378: } else {
18379: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
18380: }
18381: } else if(strncmp(tmp, "PATH=", 5) == 0) {
18382: if(env_path[0] != '\0') {
18383: sprintf(tmp, "PATH=%s", env_path);
18384: } else {
18385: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
18386: }
18387: path_added = 1;
18388: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
18389: prompt_added = 1;
18390: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
18391: if(env_temp[0] != '\0') {
18392: sprintf(tmp, "TEMP=%s", env_temp);
18393: } else {
18394: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
18395: }
18396: temp_added = 1;
18397: } else if(strncmp(tmp, "TMP=", 4) == 0) {
18398: if(env_temp[0] != '\0') {
18399: sprintf(tmp, "TMP=%s", env_temp);
18400: } else {
18401: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
18402: }
18403: tmp_added = 1;
18404: } else if(strncmp(tmp, "TZ=", 3) == 0) {
18405: char *env = getenv("MSDOS_TZ");
18406: if(env != NULL) {
18407: sprintf(tmp, "TZ=%s", env);
18408: }
18409: tz_added = 1;
18410: }
18411: int len = strlen(tmp);
18412: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
18413: fatalerror("too many environments\n");
18414: }
18415: memcpy(mem + (seg << 4) + ofs, tmp, len);
18416: ofs += len + 1;
18417: }
18418: }
18419: if(!append_added && env_append[0] != '\0') {
18420: #define SET_ENV(name, value) { \
18421: char tmp[ENV_SIZE]; \
18422: sprintf(tmp, "%s=%s", name, value); \
18423: int len = strlen(tmp); \
18424: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
18425: fatalerror("too many environments\n"); \
18426: } \
18427: memcpy(mem + (seg << 4) + ofs, tmp, len); \
18428: ofs += len + 1; \
18429: }
18430: SET_ENV("APPEND", env_append);
18431: }
18432: if(!comspec_added) {
18433: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
18434: }
18435: if(!lastdrive_added) {
18436: SET_ENV("LASTDRIVE", "Z");
18437: }
18438: if(!path_added) {
18439: SET_ENV("PATH", env_path);
18440: }
18441: if(!prompt_added) {
18442: SET_ENV("PROMPT", "$P$G");
18443: }
18444: if(!temp_added) {
18445: SET_ENV("TEMP", env_temp);
18446: }
18447: if(!tmp_added) {
18448: SET_ENV("TMP", env_temp);
18449: }
18450: if(!tz_added) {
18451: TIME_ZONE_INFORMATION tzi;
18452: HKEY hKey, hSubKey;
18453: char tzi_std_name[64];
18454: char tz_std[8] = "GMT";
18455: char tz_dlt[8] = "GST";
18456: char tz_value[32];
18457:
18458: // timezone name from GetTimeZoneInformation may not be english
18459: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
18460: setlocale(LC_CTYPE, "");
18461: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
18462:
18463: // get english timezone name from registry
18464: if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
18465: for(DWORD i = 0; !tz_added; i++) {
18466: char reg_name[256], sub_key[1024], std_name[256];
18467: DWORD size;
18468: FILETIME ftTime;
18469: LONG result = RegEnumKeyExA(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
18470:
18471: if(result == ERROR_SUCCESS) {
18472: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
18473: if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
18474: if(RegQueryValueExA(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
18475: // search english timezone name from table
18476: if(strcmp(std_name, tzi_std_name) == 0) {
18477: for(int j = 0; j < array_length(tz_table); j++) {
18478: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
18479: if(tz_table[j].std != NULL) {
18480: strcpy(tz_std, tz_table[j].std);
18481: }
18482: if(tz_table[j].dlt != NULL) {
18483: strcpy(tz_dlt, tz_table[j].dlt);
18484: }
18485: tz_added = 1;
18486: break;
18487: }
18488: }
18489: }
18490: }
18491: RegCloseKey(hSubKey);
18492: }
18493: } else if(result == ERROR_NO_MORE_ITEMS) {
18494: break;
18495: }
18496: }
18497: RegCloseKey(hKey);
18498: }
18499: if((tzi.Bias % 60) != 0) {
18500: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
18501: } else {
18502: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
18503: }
18504: if(daylight) {
18505: strcat(tz_value, tz_dlt);
18506: }
18507: SET_ENV("TZ", tz_value);
18508: }
18509: seg += (ENV_SIZE >> 4);
18510:
18511: // psp
18512: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
18513: current_psp = seg;
18514: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
18515: psp->parent_psp = current_psp;
18516: seg += (PSP_SIZE >> 4);
18517:
18518: // first free mcb in conventional memory
18519: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
18520: first_mcb = seg;
18521:
18522: // dummy mcb to link to umb
18523: #if 0
18524: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); // link umb
18525: #else
18526: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); // unlink umb
18527: #endif
18528:
18529: // first free mcb in upper memory block
18530: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
18531:
18532: #ifdef SUPPORT_HMA
18533: // first free mcb in high memory area
18534: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
18535: #endif
18536:
18537: // interrupt vector
18538: for(int i = 0; i < 256; i++) {
18539: // 00-07: CPU exception handler
18540: // 08-0F: IRQ 0-7
18541: // 10-1F: PC BIOS
18542: // 20-3F: MS-DOS system call
18543: // 70-77: IRQ 8-15
18544: *(UINT16 *)(mem + 4 * i + 0) = (i <= 0x3f || (i >= 0x70 && i <= 0x77)) ? (IRET_SIZE + 5 * i) : i;
18545: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
18546: }
18547: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffc:0018 irq0 (system timer)
18548: *(UINT16 *)(mem + 4 * 0x08 + 2) = DUMMY_TOP >> 4;
18549: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
18550: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
18551: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
18552: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
18553: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffc:0000 irq12 (mouse)
18554: *(UINT16 *)(mem + 4 * 0x74 + 2) = DUMMY_TOP >> 4;
18555:
18556: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
18557: static const struct {
18558: UINT16 attributes;
18559: char *dev_name;
18560: } dummy_devices[] = {
18561: {0x8013, "CON "},
18562: {0x8000, "AUX "},
18563: {0xa0c0, "PRN "},
18564: {0x8008, "CLOCK$ "},
18565: {0x8000, "COM1 "},
18566: {0xa0c0, "LPT1 "},
18567: {0xa0c0, "LPT2 "},
18568: {0xa0c0, "LPT3 "},
18569: {0x8000, "COM2 "},
18570: {0x8000, "COM3 "},
18571: {0x8000, "COM4 "},
18572: // {0xc000, "CONFIG$ "},
18573: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
18574: };
18575: static const UINT8 dummy_device_routine[] = {
18576: // from NUL device of Windows 98 SE
18577: // or word ptr ES:[BX+03],0100
18578: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
18579: // retf
18580: 0xcb,
18581: };
18582: device_t *last = NULL;
18583: for(int i = 0; i < array_length(dummy_devices); i++) {
18584: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
18585: device->next_driver.w.l = 22 + 18 * (i + 1);
18586: device->next_driver.w.h = DEVICE_TOP >> 4;
18587: device->attributes = dummy_devices[i].attributes;
18588: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
18589: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
18590: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
18591: last = device;
18592: }
18593: if(last != NULL) {
18594: last->next_driver.w.l = 0;
18595: last->next_driver.w.h = XMS_TOP >> 4;
18596: }
18597: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
18598:
18599: // dos info
18600: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
18601: dos_info->magic_word = 1;
18602: dos_info->first_mcb = MEMORY_TOP >> 4;
18603: dos_info->first_dpb.w.l = 0;
18604: dos_info->first_dpb.w.h = DPB_TOP >> 4;
18605: dos_info->first_sft.w.l = 0;
18606: dos_info->first_sft.w.h = SFT_TOP >> 4;
18607: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 4th device in IO.SYS
18608: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
18609: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
18610: dos_info->con_device.w.h = DEVICE_TOP >> 4;
18611: dos_info->max_sector_len = 512;
18612: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
18613: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
18614: dos_info->cds.w.l = 0;
18615: dos_info->cds.w.h = CDS_TOP >> 4;
18616: dos_info->fcb_table.w.l = 0;
18617: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
18618: dos_info->last_drive = 'Z' - 'A' + 1;
18619: dos_info->buffers_x = 20;
18620: dos_info->buffers_y = 0;
18621: dos_info->boot_drive = 'C' - 'A' + 1;
18622: dos_info->nul_device.next_driver.w.l = 22;
18623: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
18624: dos_info->nul_device.attributes = 0x8004;
18625: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
18626: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
18627: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
18628: dos_info->disk_buf_heads.w.l = 0;
18629: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
18630: dos_info->umb_linked = (((mcb_t *)(mem + MEMORY_END - 16))->mz == 'M' ? 0x01 : 0x00);
18631: dos_info->first_umb_fcb = UMB_TOP >> 4;
18632: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
18633: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
18634:
18635: char *env;
18636: if((env = getenv("LASTDRIVE")) != NULL) {
18637: if(env[0] >= 'A' && env[0] <= 'Z') {
18638: dos_info->last_drive = env[0] - 'A' + 1;
18639: } else if(env[0] >= 'a' && env[0] <= 'z') {
18640: dos_info->last_drive = env[0] - 'a' + 1;
18641: }
18642: }
18643: if((env = getenv("windir")) != NULL) {
18644: if(env[0] >= 'A' && env[0] <= 'Z') {
18645: dos_info->boot_drive = env[0] - 'A' + 1;
18646: } else if(env[0] >= 'a' && env[0] <= 'z') {
18647: dos_info->boot_drive = env[0] - 'a' + 1;
18648: }
18649: }
18650: #if defined(HAS_I386)
18651: dos_info->i386_or_later = 1;
18652: #else
18653: dos_info->i386_or_later = 0;
18654: #endif
18655: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
18656:
18657: // ems (int 67h) and xms
18658: device_t *xms_device = (device_t *)(mem + XMS_TOP);
18659: xms_device->next_driver.w.l = 0xffff;
18660: xms_device->next_driver.w.h = 0xffff;
18661: xms_device->attributes = 0xc000;
18662: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
18663: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
18664: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
18665:
18666: mem[XMS_TOP + 0x12] = 0xcd; // int 65h (dummy)
18667: mem[XMS_TOP + 0x13] = 0x65;
18668: mem[XMS_TOP + 0x14] = 0xcf; // iret
18669: #ifdef SUPPORT_XMS
18670: if(support_xms) {
18671: mem[XMS_TOP + 0x15] = 0xcd; // int 66h (dummy)
18672: mem[XMS_TOP + 0x16] = 0x66;
18673: mem[XMS_TOP + 0x17] = 0xcb; // retf
18674: } else
18675: #endif
18676: mem[XMS_TOP + 0x15] = 0xcb; // retf
18677: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
18678:
18679: // irq12 routine (mouse)
18680: mem[DUMMY_TOP + 0x00] = 0xcd; // int 69h (dummy)
18681: mem[DUMMY_TOP + 0x01] = 0x69;
18682: mem[DUMMY_TOP + 0x02] = 0x9a; // call far mouse
18683: mem[DUMMY_TOP + 0x03] = 0xff;
18684: mem[DUMMY_TOP + 0x04] = 0xff;
18685: mem[DUMMY_TOP + 0x05] = 0xff;
18686: mem[DUMMY_TOP + 0x06] = 0xff;
18687: // mem[DUMMY_TOP + 0x07] = 0xcd; // int 6ah (dummy)
18688: // mem[DUMMY_TOP + 0x08] = 0x6a;
18689: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy)
18690: mem[DUMMY_TOP + 0x08] = 0x6b;
18691: mem[DUMMY_TOP + 0x09] = 0xcf; // iret
18692:
18693: // case map routine
18694: mem[DUMMY_TOP + 0x0a] = 0xcd; // int 6ch (dummy)
18695: mem[DUMMY_TOP + 0x0b] = 0x6c;
18696: mem[DUMMY_TOP + 0x0c] = 0xcb; // retf
18697:
18698: // font read routine
18699: mem[DUMMY_TOP + 0x0d] = 0xcd; // int 6dh (dummy)
18700: mem[DUMMY_TOP + 0x0e] = 0x6d;
18701: mem[DUMMY_TOP + 0x0f] = 0xcb; // retf
18702:
18703: // error message read routine
18704: mem[DUMMY_TOP + 0x10] = 0xcd; // int 6eh (dummy)
18705: mem[DUMMY_TOP + 0x11] = 0x6e;
18706: mem[DUMMY_TOP + 0x12] = 0xcb; // retf
18707:
18708: // dummy loop to wait BIOS/DOS service is done
18709: mem[DUMMY_TOP + 0x13] = 0xe6; // out f7h, al
18710: mem[DUMMY_TOP + 0x14] = 0xf7;
18711: mem[DUMMY_TOP + 0x15] = 0x78; // js/jns -4
18712: mem[DUMMY_TOP + 0x16] = 0xfc;
18713: mem[DUMMY_TOP + 0x17] = 0xcb; // retf
18714:
18715: // irq0 routine (system timer)
18716: mem[DUMMY_TOP + 0x18] = 0xcd; // int 1ch
18717: mem[DUMMY_TOP + 0x19] = 0x1c;
18718: mem[DUMMY_TOP + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008
18719: mem[DUMMY_TOP + 0x1b] = 0x08;
18720: mem[DUMMY_TOP + 0x1c] = 0x00;
18721: mem[DUMMY_TOP + 0x1d] = ((IRET_TOP >> 4) ) & 0xff;
18722: mem[DUMMY_TOP + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff;
18723:
18724: // alter page map and call routine
18725: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far
18726: mem[DUMMY_TOP + 0x20] = 0xff;
18727: mem[DUMMY_TOP + 0x21] = 0xff;
18728: mem[DUMMY_TOP + 0x22] = 0xff;
18729: mem[DUMMY_TOP + 0x23] = 0xff;
18730: mem[DUMMY_TOP + 0x24] = 0xcd; // int 6fh (dummy)
18731: mem[DUMMY_TOP + 0x25] = 0x6f;
18732: mem[DUMMY_TOP + 0x26] = 0xcb; // retf
18733:
18734: // call int 29h routine
18735: mem[DUMMY_TOP + 0x27] = 0xcd; // int 29h
18736: mem[DUMMY_TOP + 0x28] = 0x29;
18737: mem[DUMMY_TOP + 0x29] = 0xcb; // retf
18738:
18739: // VCPI entry point
18740: mem[DUMMY_TOP + 0x2a] = 0xcd; // int 65h
18741: mem[DUMMY_TOP + 0x2b] = 0x65;
18742: mem[DUMMY_TOP + 0x2c] = 0xcb; // retf
18743:
18744: // boot routine
18745: mem[0xffff0 + 0x00] = 0xf4; // halt to exit MS-DOS Player
18746: #if 1
18747: mem[0xffff0 + 0x05] = '0'; // rom date (same as DOSBox)
18748: mem[0xffff0 + 0x06] = '1';
18749: mem[0xffff0 + 0x07] = '/';
18750: mem[0xffff0 + 0x08] = '0';
18751: mem[0xffff0 + 0x09] = '1';
18752: mem[0xffff0 + 0x0a] = '/';
18753: mem[0xffff0 + 0x0b] = '9';
18754: mem[0xffff0 + 0x0c] = '2';
18755: mem[0xffff0 + 0x0e] = 0xfc; // machine id (pc/at)
18756: mem[0xffff0 + 0x0f] = 0x55; // signature
18757: #else
18758: mem[0xffff0 + 0x05] = '0'; // rom date (same as Windows 98 SE)
18759: mem[0xffff0 + 0x06] = '2';
18760: mem[0xffff0 + 0x07] = '/';
18761: mem[0xffff0 + 0x08] = '2';
18762: mem[0xffff0 + 0x09] = '2';
18763: mem[0xffff0 + 0x0a] = '/';
18764: mem[0xffff0 + 0x0b] = '0';
18765: mem[0xffff0 + 0x0c] = '6';
18766: mem[0xffff0 + 0x0e] = 0xfc; // machine id (pc/at)
18767: mem[0xffff0 + 0x0f] = 0x00;
18768: #endif
18769:
18770: // param block
18771: // + 0: param block (22bytes)
18772: // +24: fcb1/2 (20bytes)
18773: // +44: command tail (128bytes)
18774: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
18775: param->env_seg = 0;
18776: param->cmd_line.w.l = 44;
18777: param->cmd_line.w.h = (WORK_TOP >> 4);
18778: param->fcb1.w.l = 24;
18779: param->fcb1.w.h = (WORK_TOP >> 4);
18780: param->fcb2.w.l = 24;
18781: param->fcb2.w.h = (WORK_TOP >> 4);
18782:
18783: memset(mem + WORK_TOP + 24, 0x20, 20);
18784:
18785: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
18786: if(argc > 1) {
18787: sprintf(cmd_line->cmd, " %s", argv[1]);
18788: for(int i = 2; i < argc; i++) {
18789: char tmp[128];
18790: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
18791: strcpy(cmd_line->cmd, tmp);
18792: }
18793: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
18794: } else {
18795: cmd_line->len = 0;
18796: }
18797: cmd_line->cmd[cmd_line->len] = 0x0d;
18798:
18799: // system file table
18800: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
18801: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
18802:
18803: // disk buffer header (from DOSBox)
18804: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
18805: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
18806: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
18807: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
18808: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
18809:
18810: // fcb table
18811: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
18812: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
18813:
18814: // drive parameter block
18815: for(int i = 0; i < 2; i++) {
18816: // may be a floppy drive
18817: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * i);
18818: sprintf(cds->path_name, "%c:\\", 'A' + i);
18819: cds->drive_attrib = 0x4000; // physical drive
18820: cds->dpb_ptr.w.l = sizeof(dpb_t) * i;
18821: cds->dpb_ptr.w.h = DPB_TOP >> 4;
18822: cds->word_1 = cds->word_2 = cds->word_3 = 0xffff;
18823: cds->bs_offset = 2;
18824:
18825: dpb_t *dpb = (dpb_t *)(mem + DPB_TOP + sizeof(dpb_t) * i);
18826: dpb->drive_num = i;
18827: dpb->unit_num = i;
18828: dpb->next_dpb_ofs = /*(i == 25) ? 0xffff : */sizeof(dpb_t) * (i + 1);
18829: dpb->next_dpb_seg = /*(i == 25) ? 0xffff : */DPB_TOP >> 4;
18830: }
18831: for(int i = 2; i < 26; i++) {
18832: msdos_cds_update(i);
18833: UINT16 seg, ofs;
18834: msdos_drive_param_block_update(i, &seg, &ofs, 1);
18835: }
18836:
18837: // nls stuff
18838: msdos_nls_tables_init();
18839:
18840: // execute command
18841: try {
18842: if(msdos_process_exec(argv[0], param, 0, true)) {
18843: fatalerror("'%s' not found\n", argv[0]);
18844: }
18845: } catch(...) {
18846: // we should not reach here :-(
18847: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
18848: }
18849: retval = 0;
18850: return(0);
18851: }
18852:
18853: #define remove_std_file(path) { \
18854: int fd = _open(path, _O_RDONLY | _O_BINARY); \
18855: if(fd != -1) { \
18856: _lseek(fd, 0, SEEK_END); \
18857: int size = _tell(fd); \
18858: _close(fd); \
18859: if(size == 0) { \
18860: remove(path); \
18861: } \
18862: } \
18863: }
18864:
18865: void msdos_finish()
18866: {
18867: for(int i = 0; i < MAX_FILES; i++) {
18868: if(file_handler[i].valid) {
18869: _close(i);
18870: }
18871: }
18872: #ifdef MAP_AUX_DEVICE_TO_FILE
18873: remove_std_file("stdaux.txt");
18874: #endif
18875: #ifdef SUPPORT_XMS
18876: msdos_xms_finish();
18877: #endif
18878: msdos_dbcs_table_finish();
18879: }
18880:
18881: /* ----------------------------------------------------------------------------
18882: PC/AT hardware emulation
18883: ---------------------------------------------------------------------------- */
18884:
18885: void hardware_init()
18886: {
18887: CPU_INIT_CALL(CPU_MODEL);
18888: CPU_RESET_CALL(CPU_MODEL);
18889: m_IF = 1;
18890: #if defined(HAS_I386)
18891: cpu_type = (REG32(EDX) >> 8) & 0x0f;
18892: cpu_step = (REG32(EDX) >> 0) & 0x0f;
18893: #endif
18894: i386_set_a20_line(0);
18895:
18896: ems_init();
18897: dma_init();
18898: pic_init();
18899: pio_init();
18900: #ifdef PIT_ALWAYS_RUNNING
18901: pit_init();
18902: #else
18903: pit_active = 0;
18904: #endif
18905: sio_init();
18906: cmos_init();
18907: kbd_init();
18908: }
18909:
18910: void hardware_finish()
18911: {
18912: #if defined(HAS_I386)
18913: vtlb_free(m_vtlb);
18914: #endif
18915: ems_finish();
18916: pio_finish();
18917: sio_finish();
18918: }
18919:
18920: void hardware_release()
18921: {
18922: // release hardware resources when this program will be terminated abnormally
18923: #ifdef EXPORT_DEBUG_TO_FILE
18924: if(fp_debug_log != NULL) {
18925: fclose(fp_debug_log);
18926: fp_debug_log = NULL;
18927: }
18928: #endif
18929: #if defined(HAS_I386)
18930: vtlb_free(m_vtlb);
18931: #endif
18932: ems_release();
18933: pio_release();
18934: sio_release();
18935: }
18936:
18937: void hardware_run()
18938: {
18939: #ifdef EXPORT_DEBUG_TO_FILE
18940: // open debug log file after msdos_init() is done not to use the standard file handlers
18941: fp_debug_log = fopen("debug.log", "w");
18942: #endif
18943: #ifdef USE_DEBUGGER
18944: m_int_num = -1;
18945: #endif
18946: while(!m_exit) {
18947: hardware_run_cpu();
18948: }
18949: #ifdef EXPORT_DEBUG_TO_FILE
18950: if(fp_debug_log != NULL) {
18951: fclose(fp_debug_log);
18952: fp_debug_log = NULL;
18953: }
18954: #endif
18955: }
18956:
18957: inline void hardware_run_cpu()
18958: {
18959: #if defined(HAS_I386)
18960: CPU_EXECUTE_CALL(i386);
18961: if(m_eip != m_prev_eip) {
18962: idle_ops++;
18963: }
18964: #else
18965: CPU_EXECUTE_CALL(CPU_MODEL);
18966: if(m_pc != m_prevpc) {
18967: idle_ops++;
18968: }
18969: #endif
18970: #ifdef USE_DEBUGGER
18971: // Disallow reentering CPU_EXECUTE() in msdos_syscall()
18972: if(m_int_num >= 0) {
18973: unsigned num = (unsigned)m_int_num;
18974: m_int_num = -1;
18975: msdos_syscall(num);
18976: }
18977: #endif
18978: if(++update_ops == UPDATE_OPS) {
18979: update_ops = 0;
18980: hardware_update();
18981: }
18982: }
18983:
18984: void hardware_update()
18985: {
18986: static UINT32 prev_time = 0;
18987: UINT32 cur_time = timeGetTime();
18988:
18989: if(prev_time != cur_time) {
18990: // update pit and raise irq0
18991: #ifndef PIT_ALWAYS_RUNNING
18992: if(pit_active)
18993: #endif
18994: {
18995: if(pit_run(0, cur_time)) {
18996: pic_req(0, 0, 1);
18997: }
18998: pit_run(1, cur_time);
18999: pit_run(2, cur_time);
19000: }
19001:
19002: // update sio and raise irq4/3
19003: for(int c = 0; c < 4; c++) {
19004: sio_update(c);
19005: }
19006:
19007: // update keyboard and mouse
19008: static UINT32 prev_tick = 0;
19009: UINT32 cur_tick = cur_time / 32;
19010:
19011: if(prev_tick != cur_tick) {
19012: // update keyboard flags
19013: UINT8 state;
19014: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
19015: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
19016: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
19017: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
19018: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
19019: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
19020: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
19021: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
19022: mem[0x417] = state;
19023: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
19024: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
19025: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
19026: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
19027: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
19028: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
19029: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
19030: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
19031: mem[0x418] = state;
19032:
19033: // update console input if needed
19034: if(!key_changed || mouse.hidden == 0) {
19035: update_console_input();
19036: }
19037: if(!(kbd_status & 1)) {
19038: if(key_buf_data != NULL) {
19039: #ifdef USE_SERVICE_THREAD
19040: EnterCriticalSection(&key_buf_crit_sect);
19041: #endif
19042: if(!key_buf_data->empty()) {
19043: kbd_data = key_buf_data->read();
19044: kbd_status |= 1;
19045: key_changed = true;
19046: }
19047: #ifdef USE_SERVICE_THREAD
19048: LeaveCriticalSection(&key_buf_crit_sect);
19049: #endif
19050: }
19051: }
19052:
19053: // raise irq1 if key is pressed/released or key buffer is not empty
19054: if(!key_changed) {
19055: #ifdef USE_SERVICE_THREAD
19056: EnterCriticalSection(&key_buf_crit_sect);
19057: #endif
19058: if(!pcbios_is_key_buffer_empty()) {
19059: /*
19060: if(!(kbd_status & 1)) {
19061: UINT16 head = *(UINT16 *)(mem + 0x41a);
19062: UINT16 tail = *(UINT16 *)(mem + 0x41c);
19063: if(head != tail) {
19064: int key_char = mem[0x400 + (head++)];
19065: int key_scan = mem[0x400 + (head++)];
19066: kbd_data = key_char ? key_char : key_scan;
19067: kbd_status |= 1;
19068: }
19069: }
19070: */
19071: key_changed = true;
19072: }
19073: #ifdef USE_SERVICE_THREAD
19074: LeaveCriticalSection(&key_buf_crit_sect);
19075: #endif
19076: }
19077: if(key_changed) {
19078: pic_req(0, 1, 1);
19079: key_changed = false;
19080: }
19081:
19082: // raise irq12 if mouse status is changed
19083: if((mouse.status & 0x1f) && mouse.call_addr_ps2.dw && mouse.enabled_ps2) {
19084: mouse.status_irq = 0; // ???
19085: mouse.status_irq_alt = 0; // ???
19086: mouse.status_irq_ps2 = mouse.status & 0x1f;
19087: mouse.status = 0;
19088: pic_req(1, 4, 1);
19089: } else if((mouse.status & mouse.call_mask) && mouse.call_addr.dw) {
19090: mouse.status_irq = mouse.status & mouse.call_mask;
19091: mouse.status_irq_alt = 0; // ???
19092: mouse.status_irq_ps2 = 0; // ???
19093: mouse.status &= ~mouse.call_mask;
19094: pic_req(1, 4, 1);
19095: } else {
19096: for(int i = 0; i < 8; i++) {
19097: if((mouse.status_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
19098: mouse.status_irq = 0; // ???
19099: mouse.status_irq_alt = 0;
19100: mouse.status_irq_ps2 = 0; // ???
19101: for(int j = 0; j < 8; j++) {
19102: if((mouse.status_alt & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
19103: mouse.status_irq_alt |= (1 << j);
19104: mouse.status_alt &= ~(1 << j);
19105: }
19106: }
19107: pic_req(1, 4, 1);
19108: break;
19109: }
19110: }
19111: }
19112:
19113: prev_tick = cur_tick;
19114: }
19115:
19116: // update cursor size/position by crtc
19117: if(crtc_changed[10] != 0 || crtc_changed[11] != 0) {
19118: int size = (int)(crtc_regs[11] & 7) - (int)(crtc_regs[10] & 7) + 1;
19119: if(!((crtc_regs[10] & 0x20) != 0 || size < 0)) {
19120: ci_new.bVisible = TRUE;
19121: ci_new.dwSize = (size + 2) * 100 / (8 + 2);
19122: } else {
19123: ci_new.bVisible = FALSE;
19124: }
19125: crtc_changed[10] = crtc_changed[11] = 0;
19126: }
19127: if(crtc_changed[14] != 0 || crtc_changed[15] != 0) {
19128: if(cursor_moved) {
19129: pcbios_update_cursor_position();
19130: cursor_moved = false;
19131: }
19132: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
19133: int position = crtc_regs[14] * 256 + crtc_regs[15];
19134: int width = *(UINT16 *)(mem + 0x44a);
19135: COORD co;
19136: co.X = position % width;
19137: co.Y = position / width + scr_top;
19138: SetConsoleCursorPosition(hStdout, co);
19139:
19140: crtc_changed[14] = crtc_changed[15] = 0;
19141: cursor_moved_by_crtc = true;
19142: }
19143:
19144: // update cursor info
19145: if(!is_cursor_blink_off()) {
19146: ci_new.bVisible = TRUE;
19147: }
19148: if(!(ci_old.dwSize == ci_new.dwSize && ci_old.bVisible == ci_new.bVisible)) {
19149: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
19150: SetConsoleCursorInfo(hStdout, &ci_new);
19151: }
19152: ci_old = ci_new;
19153:
19154: // update daily timer counter
19155: pcbios_update_daily_timer_counter(cur_time);
19156:
19157: prev_time = cur_time;
19158: }
19159: }
19160:
19161: // ems
19162:
19163: void ems_init()
19164: {
19165: memset(ems_handles, 0, sizeof(ems_handles));
19166: memset(ems_pages, 0, sizeof(ems_pages));
19167: free_ems_pages = MAX_EMS_PAGES;
19168: }
19169:
19170: void ems_finish()
19171: {
19172: ems_release();
19173: }
19174:
19175: void ems_release()
19176: {
19177: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
19178: if(ems_handles[i].buffer != NULL) {
19179: free(ems_handles[i].buffer);
19180: ems_handles[i].buffer = NULL;
19181: }
19182: }
19183: }
19184:
19185: void ems_allocate_pages(int handle, int pages)
19186: {
19187: if(pages > 0) {
19188: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
19189: } else {
19190: ems_handles[handle].buffer = NULL;
19191: }
19192: ems_handles[handle].pages = pages;
19193: ems_handles[handle].allocated = true;
19194: free_ems_pages -= pages;
19195: }
19196:
19197: void ems_reallocate_pages(int handle, int pages)
19198: {
19199: if(ems_handles[handle].allocated) {
19200: if(ems_handles[handle].pages != pages) {
19201: UINT8 *new_buffer = NULL;
19202:
19203: if(pages > 0) {
19204: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
19205: }
19206: if(ems_handles[handle].buffer != NULL) {
19207: if(new_buffer != NULL) {
19208: if(pages > ems_handles[handle].pages) {
19209: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
19210: } else {
19211: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
19212: }
19213: }
19214: free(ems_handles[handle].buffer);
19215: ems_handles[handle].buffer = NULL;
19216: }
19217: free_ems_pages += ems_handles[handle].pages;
19218:
19219: ems_handles[handle].buffer = new_buffer;
19220: ems_handles[handle].pages = pages;
19221: free_ems_pages -= pages;
19222: }
19223: } else {
19224: ems_allocate_pages(handle, pages);
19225: }
19226: }
19227:
19228: void ems_release_pages(int handle)
19229: {
19230: if(ems_handles[handle].allocated) {
19231: if(ems_handles[handle].buffer != NULL) {
19232: free(ems_handles[handle].buffer);
19233: ems_handles[handle].buffer = NULL;
19234: }
19235: free_ems_pages += ems_handles[handle].pages;
19236: ems_handles[handle].allocated = false;
19237: }
19238: }
19239:
19240: void ems_map_page(int physical, int handle, int logical)
19241: {
19242: if(ems_pages[physical].mapped) {
19243: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
19244: return;
19245: }
19246: ems_unmap_page(physical);
19247: }
19248: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
19249: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
19250: }
19251: ems_pages[physical].handle = handle;
19252: ems_pages[physical].page = logical;
19253: ems_pages[physical].mapped = true;
19254: }
19255:
19256: void ems_unmap_page(int physical)
19257: {
19258: if(ems_pages[physical].mapped) {
19259: int handle = ems_pages[physical].handle;
19260: int logical = ems_pages[physical].page;
19261:
19262: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
19263: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
19264: }
19265: ems_pages[physical].mapped = false;
19266: }
19267: }
19268:
19269: // dma
19270:
19271: void dma_init()
19272: {
19273: memset(dma, 0, sizeof(dma));
19274: for(int c = 0; c < 2; c++) {
19275: // for(int ch = 0; ch < 4; ch++) {
19276: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
19277: // }
19278: dma_reset(c);
19279: }
19280: }
19281:
19282: void dma_reset(int c)
19283: {
19284: dma[c].low_high = false;
19285: dma[c].cmd = dma[c].req = dma[c].tc = 0;
19286: dma[c].mask = 0xff;
19287: }
19288:
19289: void dma_write(int c, UINT32 addr, UINT8 data)
19290: {
19291: int ch = (addr >> 1) & 3;
19292: UINT8 bit = 1 << (data & 3);
19293:
19294: switch(addr & 0x0f) {
19295: case 0x00: case 0x02: case 0x04: case 0x06:
19296: if(dma[c].low_high) {
19297: dma[c].ch[ch].bareg.b.h = data;
19298: } else {
19299: dma[c].ch[ch].bareg.b.l = data;
19300: }
19301: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
19302: dma[c].low_high = !dma[c].low_high;
19303: break;
19304: case 0x01: case 0x03: case 0x05: case 0x07:
19305: if(dma[c].low_high) {
19306: dma[c].ch[ch].bcreg.b.h = data;
19307: } else {
19308: dma[c].ch[ch].bcreg.b.l = data;
19309: }
19310: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
19311: dma[c].low_high = !dma[c].low_high;
19312: break;
19313: case 0x08:
19314: // command register
19315: dma[c].cmd = data;
19316: break;
19317: case 0x09:
19318: // dma[c].request register
19319: if(data & 4) {
19320: if(!(dma[c].req & bit)) {
19321: dma[c].req |= bit;
19322: // dma_run(c, ch);
19323: }
19324: } else {
19325: dma[c].req &= ~bit;
19326: }
19327: break;
19328: case 0x0a:
19329: // single mask register
19330: if(data & 4) {
19331: dma[c].mask |= bit;
19332: } else {
19333: dma[c].mask &= ~bit;
19334: }
19335: break;
19336: case 0x0b:
19337: // mode register
19338: dma[c].ch[data & 3].mode = data;
19339: break;
19340: case 0x0c:
19341: dma[c].low_high = false;
19342: break;
19343: case 0x0d:
19344: // clear master
19345: dma_reset(c);
19346: break;
19347: case 0x0e:
19348: // clear mask register
19349: dma[c].mask = 0;
19350: break;
19351: case 0x0f:
19352: // all mask register
19353: dma[c].mask = data & 0x0f;
19354: break;
19355: }
19356: }
19357:
19358: UINT8 dma_read(int c, UINT32 addr)
19359: {
19360: int ch = (addr >> 1) & 3;
19361: UINT8 val = 0xff;
19362:
19363: switch(addr & 0x0f) {
19364: case 0x00: case 0x02: case 0x04: case 0x06:
19365: if(dma[c].low_high) {
19366: val = dma[c].ch[ch].areg.b.h;
19367: } else {
19368: val = dma[c].ch[ch].areg.b.l;
19369: }
19370: dma[c].low_high = !dma[c].low_high;
19371: return(val);
19372: case 0x01: case 0x03: case 0x05: case 0x07:
19373: if(dma[c].low_high) {
19374: val = dma[c].ch[ch].creg.b.h;
19375: } else {
19376: val = dma[c].ch[ch].creg.b.l;
19377: }
19378: dma[c].low_high = !dma[c].low_high;
19379: return(val);
19380: case 0x08:
19381: // status register
19382: val = (dma[c].req << 4) | dma[c].tc;
19383: dma[c].tc = 0;
19384: return(val);
19385: case 0x0d:
19386: // temporary register (intel 82374 does not support)
19387: return(dma[c].tmp & 0xff);
19388: case 0x0f:
19389: // mask register (intel 82374 does support)
19390: return(dma[c].mask);
19391: }
19392: return(0xff);
19393: }
19394:
19395: void dma_page_write(int c, int ch, UINT8 data)
19396: {
19397: dma[c].ch[ch].pagereg = data;
19398: }
19399:
19400: UINT8 dma_page_read(int c, int ch)
19401: {
19402: return(dma[c].ch[ch].pagereg);
19403: }
19404:
19405: void dma_run(int c, int ch)
19406: {
19407: UINT8 bit = 1 << ch;
19408:
19409: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
19410: // execute dma
19411: while(dma[c].req & bit) {
19412: if(ch == 0 && (dma[c].cmd & 0x01)) {
19413: // memory -> memory
19414: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
19415: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
19416:
19417: if(c == 0) {
19418: dma[c].tmp = read_byte(saddr);
19419: write_byte(daddr, dma[c].tmp);
19420: } else {
19421: dma[c].tmp = read_word(saddr << 1);
19422: write_word(daddr << 1, dma[c].tmp);
19423: }
19424: if(!(dma[c].cmd & 0x02)) {
19425: if(dma[c].ch[0].mode & 0x20) {
19426: dma[c].ch[0].areg.w--;
19427: if(dma[c].ch[0].areg.w == 0xffff) {
19428: dma[c].ch[0].pagereg--;
19429: }
19430: } else {
19431: dma[c].ch[0].areg.w++;
19432: if(dma[c].ch[0].areg.w == 0) {
19433: dma[c].ch[0].pagereg++;
19434: }
19435: }
19436: }
19437: if(dma[c].ch[1].mode & 0x20) {
19438: dma[c].ch[1].areg.w--;
19439: if(dma[c].ch[1].areg.w == 0xffff) {
19440: dma[c].ch[1].pagereg--;
19441: }
19442: } else {
19443: dma[c].ch[1].areg.w++;
19444: if(dma[c].ch[1].areg.w == 0) {
19445: dma[c].ch[1].pagereg++;
19446: }
19447: }
19448:
19449: // check dma condition
19450: if(dma[c].ch[0].creg.w-- == 0) {
19451: if(dma[c].ch[0].mode & 0x10) {
19452: // self initialize
19453: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
19454: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
19455: } else {
19456: // dma[c].mask |= bit;
19457: }
19458: }
19459: if(dma[c].ch[1].creg.w-- == 0) {
19460: // terminal count
19461: if(dma[c].ch[1].mode & 0x10) {
19462: // self initialize
19463: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
19464: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
19465: } else {
19466: dma[c].mask |= bit;
19467: }
19468: dma[c].req &= ~bit;
19469: dma[c].tc |= bit;
19470: }
19471: } else {
19472: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
19473:
19474: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
19475: // verify
19476: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
19477: // io -> memory
19478: if(c == 0) {
19479: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
19480: write_byte(addr, dma[c].tmp);
19481: } else {
19482: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
19483: write_word(addr << 1, dma[c].tmp);
19484: }
19485: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
19486: // memory -> io
19487: if(c == 0) {
19488: dma[c].tmp = read_byte(addr);
19489: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
19490: } else {
19491: dma[c].tmp = read_word(addr << 1);
19492: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
19493: }
19494: }
19495: if(dma[c].ch[ch].mode & 0x20) {
19496: dma[c].ch[ch].areg.w--;
19497: if(dma[c].ch[ch].areg.w == 0xffff) {
19498: dma[c].ch[ch].pagereg--;
19499: }
19500: } else {
19501: dma[c].ch[ch].areg.w++;
19502: if(dma[c].ch[ch].areg.w == 0) {
19503: dma[c].ch[ch].pagereg++;
19504: }
19505: }
19506:
19507: // check dma condition
19508: if(dma[c].ch[ch].creg.w-- == 0) {
19509: // terminal count
19510: if(dma[c].ch[ch].mode & 0x10) {
19511: // self initialize
19512: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
19513: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
19514: } else {
19515: dma[c].mask |= bit;
19516: }
19517: dma[c].req &= ~bit;
19518: dma[c].tc |= bit;
19519: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
19520: // single mode
19521: break;
19522: }
19523: }
19524: }
19525: }
19526: }
19527:
19528: // pic
19529:
19530: void pic_init()
19531: {
19532: memset(pic, 0, sizeof(pic));
19533: pic[0].imr = pic[1].imr = 0xff;
19534:
19535: // from bochs bios
19536: pic_write(0, 0, 0x11); // icw1 = 11h
19537: pic_write(0, 1, 0x08); // icw2 = 08h
19538: pic_write(0, 1, 0x04); // icw3 = 04h
19539: pic_write(0, 1, 0x01); // icw4 = 01h
19540: pic_write(0, 1, 0xb8); // ocw1 = b8h
19541: pic_write(1, 0, 0x11); // icw1 = 11h
19542: pic_write(1, 1, 0x70); // icw2 = 70h
19543: pic_write(1, 1, 0x02); // icw3 = 02h
19544: pic_write(1, 1, 0x01); // icw4 = 01h
19545: }
19546:
19547: void pic_write(int c, UINT32 addr, UINT8 data)
19548: {
19549: if(addr & 1) {
19550: if(pic[c].icw2_r) {
19551: // icw2
19552: pic[c].icw2 = data;
19553: pic[c].icw2_r = 0;
19554: } else if(pic[c].icw3_r) {
19555: // icw3
19556: pic[c].icw3 = data;
19557: pic[c].icw3_r = 0;
19558: } else if(pic[c].icw4_r) {
19559: // icw4
19560: pic[c].icw4 = data;
19561: pic[c].icw4_r = 0;
19562: } else {
19563: // ocw1
19564: pic[c].imr = data;
19565: }
19566: } else {
19567: if(data & 0x10) {
19568: // icw1
19569: pic[c].icw1 = data;
19570: pic[c].icw2_r = 1;
19571: pic[c].icw3_r = (data & 2) ? 0 : 1;
19572: pic[c].icw4_r = data & 1;
19573: pic[c].irr = 0;
19574: pic[c].isr = 0;
19575: pic[c].imr = 0;
19576: pic[c].prio = 0;
19577: if(!(pic[c].icw1 & 1)) {
19578: pic[c].icw4 = 0;
19579: }
19580: pic[c].ocw3 = 0;
19581: } else if(data & 8) {
19582: // ocw3
19583: if(!(data & 2)) {
19584: data = (data & ~1) | (pic[c].ocw3 & 1);
19585: }
19586: if(!(data & 0x40)) {
19587: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
19588: }
19589: pic[c].ocw3 = data;
19590: } else {
19591: // ocw2
19592: int level = 0;
19593: if(data & 0x40) {
19594: level = data & 7;
19595: } else {
19596: if(!pic[c].isr) {
19597: return;
19598: }
19599: level = pic[c].prio;
19600: while(!(pic[c].isr & (1 << level))) {
19601: level = (level + 1) & 7;
19602: }
19603: }
19604: if(data & 0x80) {
19605: pic[c].prio = (level + 1) & 7;
19606: }
19607: if(data & 0x20) {
19608: pic[c].isr &= ~(1 << level);
19609: }
19610: }
19611: }
19612: pic_update();
19613: }
19614:
19615: UINT8 pic_read(int c, UINT32 addr)
19616: {
19617: if(addr & 1) {
19618: return(pic[c].imr);
19619: } else {
19620: // polling mode is not supported...
19621: //if(pic[c].ocw3 & 4) {
19622: // return ???;
19623: //}
19624: if(pic[c].ocw3 & 1) {
19625: return(pic[c].isr);
19626: } else {
19627: return(pic[c].irr);
19628: }
19629: }
19630: }
19631:
19632: void pic_req(int c, int level, int signal)
19633: {
19634: if(signal) {
19635: pic[c].irr |= (1 << level);
19636: } else {
19637: pic[c].irr &= ~(1 << level);
19638: }
19639: pic_update();
19640: }
19641:
19642: int pic_ack()
19643: {
19644: // ack (INTA=L)
19645: pic[pic_req_chip].isr |= pic_req_bit;
19646: pic[pic_req_chip].irr &= ~pic_req_bit;
19647: if(pic_req_chip > 0) {
19648: // update isr and irr of master
19649: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
19650: pic[pic_req_chip - 1].isr |= slave;
19651: pic[pic_req_chip - 1].irr &= ~slave;
19652: }
19653: //if(pic[pic_req_chip].icw4 & 1) {
19654: // 8086 mode
19655: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
19656: //} else {
19657: // // 8080 mode
19658: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
19659: // if(pic[pic_req_chip].icw1 & 4) {
19660: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
19661: // } else {
19662: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
19663: // }
19664: // vector = 0xcd | (addr << 8);
19665: //}
19666: if(pic[pic_req_chip].icw4 & 2) {
19667: // auto eoi
19668: pic[pic_req_chip].isr &= ~pic_req_bit;
19669: }
19670: return(vector);
19671: }
19672:
19673: void pic_update()
19674: {
19675: for(int c = 0; c < 2; c++) {
19676: UINT8 irr = pic[c].irr;
19677: if(c + 1 < 2) {
19678: // this is master
19679: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
19680: // request from slave
19681: irr |= 1 << (pic[c + 1].icw3 & 7);
19682: }
19683: }
19684: irr &= (~pic[c].imr);
19685: if(!irr) {
19686: break;
19687: }
19688: if(!(pic[c].ocw3 & 0x20)) {
19689: irr |= pic[c].isr;
19690: }
19691: int level = pic[c].prio;
19692: UINT8 bit = 1 << level;
19693: while(!(irr & bit)) {
19694: level = (level + 1) & 7;
19695: bit = 1 << level;
19696: }
19697: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
19698: // check slave
19699: continue;
19700: }
19701: if(pic[c].isr & bit) {
19702: break;
19703: }
19704: // interrupt request
19705: pic_req_chip = c;
19706: pic_req_level = level;
19707: pic_req_bit = bit;
19708: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
19709: return;
19710: }
19711: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
19712: }
19713:
19714: // pio
19715:
19716: void pio_init()
19717: {
19718: // bool conv_mode = (GetConsoleCP() == 932);
19719:
19720: memset(pio, 0, sizeof(pio));
19721:
19722: for(int c = 0; c < 2; c++) {
19723: pio[c].stat = 0xdf;
19724: pio[c].ctrl = 0x0c;
19725: // pio[c].conv_mode = conv_mode;
19726: }
19727: }
19728:
19729: void pio_finish()
19730: {
19731: pio_release();
19732: }
19733:
19734: void pio_release()
19735: {
19736: for(int c = 0; c < 2; c++) {
19737: if(pio[c].fp != NULL) {
19738: if(pio[c].jis_mode) {
19739: fputc(0x1c, pio[c].fp);
19740: fputc(0x2e, pio[c].fp);
19741: }
19742: fclose(pio[c].fp);
19743: pio[c].fp = NULL;
19744: }
19745: }
19746: }
19747:
19748: void pio_write(int c, UINT32 addr, UINT8 data)
19749: {
19750: switch(addr & 3) {
19751: case 0:
19752: pio[c].data = data;
19753: break;
19754: case 2:
19755: if((pio[c].ctrl & 0x01) && !(data & 0x01)) {
19756: // strobe H -> L
19757: if(pio[c].data == 0x0d && (data & 0x02)) {
19758: // auto feed
19759: printer_out(c, 0x0d);
19760: printer_out(c, 0x0a);
19761: } else {
19762: printer_out(c, pio[c].data);
19763: }
19764: pio[c].stat &= ~0x40; // set ack
19765: }
19766: pio[c].ctrl = data;
19767: break;
19768: }
19769: }
19770:
19771: UINT8 pio_read(int c, UINT32 addr)
19772: {
19773: switch(addr & 3) {
19774: case 0:
19775: if(pio[c].ctrl & 0x20) {
19776: // input mode
19777: return(0xff);
19778: }
19779: return(pio[c].data);
19780: case 1:
19781: {
19782: UINT8 stat = pio[c].stat;
19783: pio[c].stat |= 0x40; // clear ack
19784: return(stat);
19785: }
19786: case 2:
19787: return(pio[c].ctrl);
19788: }
19789: return(0xff);
19790: }
19791:
19792: void printer_out(int c, UINT8 data)
19793: {
19794: SYSTEMTIME time;
19795: bool jis_mode = false;
19796:
19797: GetLocalTime(&time);
19798:
19799: if(pio[c].fp != NULL) {
19800: // if at least 1000ms passed from last written, close the current file
19801: FILETIME ftime1;
19802: FILETIME ftime2;
19803: SystemTimeToFileTime(&pio[c].time, &ftime1);
19804: SystemTimeToFileTime(&time, &ftime2);
19805: INT64 *time1 = (INT64 *)&ftime1;
19806: INT64 *time2 = (INT64 *)&ftime2;
19807: INT64 msec = (*time2 - *time1) / 10000;
19808:
19809: if(msec >= 1000) {
19810: if(pio[c].jis_mode) {
19811: fputc(0x1c, pio[c].fp);
19812: fputc(0x2e, pio[c].fp);
19813: jis_mode = true;
19814: }
19815: fclose(pio[c].fp);
19816: pio[c].fp = NULL;
19817: }
19818: }
19819: if(pio[c].fp == NULL) {
19820: // create a new file in the temp folder
19821: char file_name[MAX_PATH];
19822:
19823: sprintf(file_name, "%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.PRN", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);
19824: if(GetTempPathA(MAX_PATH, pio[c].path)) {
19825: strcat(pio[c].path, file_name);
19826: } else {
19827: strcpy(pio[c].path, file_name);
19828: }
19829: pio[c].fp = fopen(pio[c].path, "w+b");
19830: }
19831: if(pio[c].fp != NULL) {
19832: if(jis_mode) {
19833: fputc(0x1c, pio[c].fp);
19834: fputc(0x26, pio[c].fp);
19835: }
19836: fputc(data, pio[c].fp);
19837:
19838: // reopen file if 1ch 26h 1ch 2eh (kanji-on kanji-off) are written at the top
19839: if(data == 0x2e && ftell(pio[c].fp) == 4) {
19840: UINT8 buffer[4];
19841: fseek(pio[c].fp, 0, SEEK_SET);
19842: fread(buffer, 4, 1, pio[c].fp);
19843: if(buffer[0] == 0x1c && buffer[1] == 0x26 && buffer[2] == 0x1c/* && buffer[3] == 0x2e*/) {
19844: fclose(pio[c].fp);
19845: pio[c].fp = fopen(pio[c].path, "w+b");
19846: }
19847: }
19848: pio[c].time = time;
19849: }
19850: }
19851:
19852: // pit
19853:
19854: #define PIT_FREQ 1193182ULL
19855: #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)
19856:
19857: void pit_init()
19858: {
19859: memset(pit, 0, sizeof(pit));
19860: for(int ch = 0; ch < 3; ch++) {
19861: pit[ch].count = 0x10000;
19862: pit[ch].ctrl_reg = 0x34;
19863: pit[ch].mode = 3;
19864: }
19865:
19866: // from bochs bios
19867: pit_write(3, 0x34);
19868: pit_write(0, 0x00);
19869: pit_write(0, 0x00);
19870: }
19871:
19872: void pit_write(int ch, UINT8 val)
19873: {
19874: #ifndef PIT_ALWAYS_RUNNING
19875: if(!pit_active) {
19876: pit_active = 1;
19877: pit_init();
19878: }
19879: #endif
19880: switch(ch) {
19881: case 0:
19882: case 1:
19883: case 2:
19884: // write count register
19885: if(!pit[ch].low_write && !pit[ch].high_write) {
19886: if(pit[ch].ctrl_reg & 0x10) {
19887: pit[ch].low_write = 1;
19888: }
19889: if(pit[ch].ctrl_reg & 0x20) {
19890: pit[ch].high_write = 1;
19891: }
19892: }
19893: if(pit[ch].low_write) {
19894: pit[ch].count_reg = val;
19895: pit[ch].low_write = 0;
19896: } else if(pit[ch].high_write) {
19897: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
19898: pit[ch].count_reg = val << 8;
19899: } else {
19900: pit[ch].count_reg |= val << 8;
19901: }
19902: pit[ch].high_write = 0;
19903: }
19904: // start count
19905: if(!pit[ch].low_write && !pit[ch].high_write) {
19906: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
19907: pit[ch].count = PIT_COUNT_VALUE(ch);
19908: pit[ch].prev_time = timeGetTime();
19909: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
19910: }
19911: }
19912: break;
19913: case 3: // ctrl reg
19914: if((val & 0xc0) == 0xc0) {
19915: // i8254 read-back command
19916: for(ch = 0; ch < 3; ch++) {
19917: if(!(val & 0x10) && !pit[ch].status_latched) {
19918: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
19919: pit[ch].status_latched = 1;
19920: }
19921: if(!(val & 0x20) && !pit[ch].count_latched) {
19922: pit_latch_count(ch);
19923: }
19924: }
19925: break;
19926: }
19927: ch = (val >> 6) & 3;
19928: if(val & 0x30) {
19929: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
19930: pit[ch].mode = modes[(val >> 1) & 7];
19931: pit[ch].count_latched = 0;
19932: pit[ch].low_read = pit[ch].high_read = 0;
19933: pit[ch].low_write = pit[ch].high_write = 0;
19934: pit[ch].ctrl_reg = val;
19935: // stop count
19936: pit[ch].prev_time = pit[ch].expired_time = 0;
19937: pit[ch].count_reg = 0;
19938: } else if(!pit[ch].count_latched) {
19939: pit_latch_count(ch);
19940: }
19941: break;
19942: }
19943: }
19944:
19945: UINT8 pit_read(int ch)
19946: {
19947: #ifndef PIT_ALWAYS_RUNNING
19948: if(!pit_active) {
19949: pit_active = 1;
19950: pit_init();
19951: }
19952: #endif
19953: switch(ch) {
19954: case 0:
19955: case 1:
19956: case 2:
19957: if(pit[ch].status_latched) {
19958: pit[ch].status_latched = 0;
19959: return(pit[ch].status);
19960: }
19961: // if not latched, through current count
19962: if(!pit[ch].count_latched) {
19963: if(!pit[ch].low_read && !pit[ch].high_read) {
19964: pit_latch_count(ch);
19965: }
19966: }
19967: // return latched count
19968: if(pit[ch].low_read) {
19969: pit[ch].low_read = 0;
19970: if(!pit[ch].high_read) {
19971: pit[ch].count_latched = 0;
19972: }
19973: return(pit[ch].latch & 0xff);
19974: } else if(pit[ch].high_read) {
19975: pit[ch].high_read = 0;
19976: pit[ch].count_latched = 0;
19977: return((pit[ch].latch >> 8) & 0xff);
19978: }
19979: }
19980: return(0xff);
19981: }
19982:
19983: int pit_run(int ch, UINT32 cur_time)
19984: {
19985: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
19986: pit[ch].count = PIT_COUNT_VALUE(ch);
19987: pit[ch].prev_time = pit[ch].expired_time;
19988: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
19989: if(cur_time >= pit[ch].expired_time) {
19990: pit[ch].prev_time = cur_time;
19991: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
19992: }
19993: return(1);
19994: }
19995: return(0);
19996: }
19997:
19998: void pit_latch_count(int ch)
19999: {
20000: if(pit[ch].expired_time != 0) {
20001: UINT32 cur_time = timeGetTime();
20002: pit_run(ch, cur_time);
20003: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
20004: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
20005:
20006: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
20007: // decrement counter in 1msec period
20008: if(pit[ch].next_latch == 0) {
20009: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
20010: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
20011: }
20012: if(pit[ch].latch > pit[ch].next_latch) {
20013: pit[ch].latch--;
20014: }
20015: } else {
20016: pit[ch].prev_latch = pit[ch].latch = latch;
20017: pit[ch].next_latch = 0;
20018: }
20019: } else {
20020: pit[ch].latch = (UINT16)pit[ch].count;
20021: pit[ch].prev_latch = pit[ch].next_latch = 0;
20022: }
20023: pit[ch].count_latched = 1;
20024: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
20025: // lower byte
20026: pit[ch].low_read = 1;
20027: pit[ch].high_read = 0;
20028: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
20029: // upper byte
20030: pit[ch].low_read = 0;
20031: pit[ch].high_read = 1;
20032: } else {
20033: // lower -> upper
20034: pit[ch].low_read = pit[ch].high_read = 1;
20035: }
20036: }
20037:
20038: int pit_get_expired_time(int ch)
20039: {
20040: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
20041: UINT64 val = pit[ch].accum >> 10;
20042: pit[ch].accum -= val << 10;
20043: return((val != 0) ? val : 1);
20044: }
20045:
20046: // sio
20047:
20048: void sio_init()
20049: {
20050: memset(sio, 0, sizeof(sio));
20051: memset(sio_mt, 0, sizeof(sio_mt));
20052:
20053: for(int c = 0; c < 4; c++) {
20054: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
20055: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
20056:
20057: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
20058: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
20059: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
20060: sio[c].set_rts = sio[c].set_dtr = true;
20061: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
20062: sio[c].irq_identify = 0x01; // no pending irq
20063:
20064: InitializeCriticalSection(&sio_mt[c].csSendData);
20065: InitializeCriticalSection(&sio_mt[c].csRecvData);
20066: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
20067: InitializeCriticalSection(&sio_mt[c].csLineStat);
20068: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
20069: InitializeCriticalSection(&sio_mt[c].csModemStat);
20070:
20071: if(sio_port_number[c] != 0) {
20072: sio[c].channel = c;
20073: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
20074: }
20075: }
20076: }
20077:
20078: void sio_finish()
20079: {
20080: for(int c = 0; c < 4; c++) {
20081: if(sio_mt[c].hThread != NULL) {
20082: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
20083: CloseHandle(sio_mt[c].hThread);
20084: sio_mt[c].hThread = NULL;
20085: }
20086: DeleteCriticalSection(&sio_mt[c].csSendData);
20087: DeleteCriticalSection(&sio_mt[c].csRecvData);
20088: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
20089: DeleteCriticalSection(&sio_mt[c].csLineStat);
20090: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
20091: DeleteCriticalSection(&sio_mt[c].csModemStat);
20092: }
20093: sio_release();
20094: }
20095:
20096: void sio_release()
20097: {
20098: for(int c = 0; c < 4; c++) {
20099: // sio_thread() may access the resources :-(
20100: bool running = (sio_mt[c].hThread != NULL);
20101:
20102: if(running) {
20103: EnterCriticalSection(&sio_mt[c].csSendData);
20104: }
20105: if(sio[c].send_buffer != NULL) {
20106: sio[c].send_buffer->release();
20107: delete sio[c].send_buffer;
20108: sio[c].send_buffer = NULL;
20109: }
20110: if(running) {
20111: LeaveCriticalSection(&sio_mt[c].csSendData);
20112: EnterCriticalSection(&sio_mt[c].csRecvData);
20113: }
20114: if(sio[c].recv_buffer != NULL) {
20115: sio[c].recv_buffer->release();
20116: delete sio[c].recv_buffer;
20117: sio[c].recv_buffer = NULL;
20118: }
20119: if(running) {
20120: LeaveCriticalSection(&sio_mt[c].csRecvData);
20121: }
20122: }
20123: }
20124:
20125: void sio_write(int c, UINT32 addr, UINT8 data)
20126: {
20127: switch(addr & 7) {
20128: case 0:
20129: if(sio[c].selector & 0x80) {
20130: if(sio[c].divisor.b.l != data) {
20131: EnterCriticalSection(&sio_mt[c].csLineCtrl);
20132: sio[c].divisor.b.l = data;
20133: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
20134: }
20135: } else {
20136: EnterCriticalSection(&sio_mt[c].csSendData);
20137: if(sio[c].send_buffer != NULL) {
20138: sio[c].send_buffer->write(data);
20139: }
20140: // transmitter holding/shift registers are not empty
20141: sio[c].line_stat_buf &= ~0x60;
20142: LeaveCriticalSection(&sio_mt[c].csSendData);
20143:
20144: if(sio[c].irq_enable & 0x02) {
20145: sio_update_irq(c);
20146: }
20147: }
20148: break;
20149: case 1:
20150: if(sio[c].selector & 0x80) {
20151: if(sio[c].divisor.b.h != data) {
20152: EnterCriticalSection(&sio_mt[c].csLineCtrl);
20153: sio[c].divisor.b.h = data;
20154: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
20155: }
20156: } else {
20157: if(sio[c].irq_enable != data) {
20158: sio[c].irq_enable = data;
20159: sio_update_irq(c);
20160: }
20161: }
20162: break;
20163: case 3:
20164: {
20165: UINT8 line_ctrl = data & 0x3f;
20166: bool set_brk = ((data & 0x40) != 0);
20167:
20168: if(sio[c].line_ctrl != line_ctrl) {
20169: EnterCriticalSection(&sio_mt[c].csLineCtrl);
20170: sio[c].line_ctrl = line_ctrl;
20171: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
20172: }
20173: if(sio[c].set_brk != set_brk) {
20174: EnterCriticalSection(&sio_mt[c].csModemCtrl);
20175: sio[c].set_brk = set_brk;
20176: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
20177: }
20178: }
20179: sio[c].selector = data;
20180: break;
20181: case 4:
20182: {
20183: bool set_dtr = ((data & 0x01) != 0);
20184: bool set_rts = ((data & 0x02) != 0);
20185:
20186: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
20187: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
20188: sio[c].set_dtr = set_dtr;
20189: sio[c].set_rts = set_rts;
20190: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
20191:
20192: bool state_changed = false;
20193:
20194: EnterCriticalSection(&sio_mt[c].csModemStat);
20195: if(set_dtr) {
20196: sio[c].modem_stat |= 0x20; // dsr on
20197: } else {
20198: sio[c].modem_stat &= ~0x20; // dsr off
20199: }
20200: if(set_rts) {
20201: sio[c].modem_stat |= 0x10; // cts on
20202: } else {
20203: sio[c].modem_stat &= ~0x10; // cts off
20204: }
20205: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
20206: if(!(sio[c].modem_stat & 0x02)) {
20207: if(sio[c].irq_enable & 0x08) {
20208: state_changed = true;
20209: }
20210: sio[c].modem_stat |= 0x02;
20211: }
20212: }
20213: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
20214: if(!(sio[c].modem_stat & 0x01)) {
20215: if(sio[c].irq_enable & 0x08) {
20216: state_changed = true;
20217: }
20218: sio[c].modem_stat |= 0x01;
20219: }
20220: }
20221: LeaveCriticalSection(&sio_mt[c].csModemStat);
20222:
20223: if(state_changed) {
20224: sio_update_irq(c);
20225: }
20226: }
20227: }
20228: sio[c].modem_ctrl = data;
20229: break;
20230: case 7:
20231: sio[c].scratch = data;
20232: break;
20233: }
20234: }
20235:
20236: UINT8 sio_read(int c, UINT32 addr)
20237: {
20238: switch(addr & 7) {
20239: case 0:
20240: if(sio[c].selector & 0x80) {
20241: return(sio[c].divisor.b.l);
20242: } else {
20243: EnterCriticalSection(&sio_mt[c].csRecvData);
20244: UINT8 data = 0;
20245: if(sio[c].recv_buffer != NULL) {
20246: data = sio[c].recv_buffer->read();
20247: }
20248: // data is not ready
20249: sio[c].line_stat_buf &= ~0x01;
20250: LeaveCriticalSection(&sio_mt[c].csRecvData);
20251:
20252: if(sio[c].irq_enable & 0x01) {
20253: sio_update_irq(c);
20254: }
20255: return(data);
20256: }
20257: case 1:
20258: if(sio[c].selector & 0x80) {
20259: return(sio[c].divisor.b.h);
20260: } else {
20261: return(sio[c].irq_enable);
20262: }
20263: case 2:
20264: return(sio[c].irq_identify);
20265: case 3:
20266: return(sio[c].selector);
20267: case 4:
20268: return(sio[c].modem_ctrl);
20269: case 5:
20270: {
20271: EnterCriticalSection(&sio_mt[c].csLineStat);
20272: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
20273: sio[c].line_stat_err = 0x00;
20274: LeaveCriticalSection(&sio_mt[c].csLineStat);
20275:
20276: bool state_changed = false;
20277:
20278: if((sio[c].line_stat_buf & 0x60) == 0x00) {
20279: EnterCriticalSection(&sio_mt[c].csSendData);
20280: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
20281: // transmitter holding register will be empty first
20282: if(sio[c].irq_enable & 0x02) {
20283: state_changed = true;
20284: }
20285: sio[c].line_stat_buf |= 0x20;
20286: }
20287: LeaveCriticalSection(&sio_mt[c].csSendData);
20288: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
20289: // transmitter shift register will be empty later
20290: sio[c].line_stat_buf |= 0x40;
20291: }
20292: if(!(sio[c].line_stat_buf & 0x01)) {
20293: EnterCriticalSection(&sio_mt[c].csRecvData);
20294: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
20295: // data is ready
20296: if(sio[c].irq_enable & 0x01) {
20297: state_changed = true;
20298: }
20299: sio[c].line_stat_buf |= 0x01;
20300: }
20301: LeaveCriticalSection(&sio_mt[c].csRecvData);
20302: }
20303: if(state_changed) {
20304: sio_update_irq(c);
20305: }
20306: return(val);
20307: }
20308: case 6:
20309: {
20310: EnterCriticalSection(&sio_mt[c].csModemStat);
20311: UINT8 val = sio[c].modem_stat;
20312: sio[c].modem_stat &= 0xf0;
20313: sio[c].prev_modem_stat = sio[c].modem_stat;
20314: LeaveCriticalSection(&sio_mt[c].csModemStat);
20315:
20316: if(sio[c].modem_ctrl & 0x10) {
20317: // loop-back
20318: val &= 0x0f;
20319: val |= (sio[c].modem_ctrl & 0x0c) << 4;
20320: val |= (sio[c].modem_ctrl & 0x01) << 5;
20321: val |= (sio[c].modem_ctrl & 0x02) << 3;
20322: }
20323: return(val);
20324: }
20325: case 7:
20326: return(sio[c].scratch);
20327: }
20328: return(0xff);
20329: }
20330:
20331: void sio_update(int c)
20332: {
20333: if((sio[c].line_stat_buf & 0x60) == 0x00) {
20334: EnterCriticalSection(&sio_mt[c].csSendData);
20335: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
20336: // transmitter holding/shift registers will be empty
20337: sio[c].line_stat_buf |= 0x60;
20338: }
20339: LeaveCriticalSection(&sio_mt[c].csSendData);
20340: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
20341: // transmitter shift register will be empty
20342: sio[c].line_stat_buf |= 0x40;
20343: }
20344: if(!(sio[c].line_stat_buf & 0x01)) {
20345: EnterCriticalSection(&sio_mt[c].csRecvData);
20346: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
20347: // data is ready
20348: sio[c].line_stat_buf |= 0x01;
20349: }
20350: LeaveCriticalSection(&sio_mt[c].csRecvData);
20351: }
20352: sio_update_irq(c);
20353: }
20354:
20355: void sio_update_irq(int c)
20356: {
20357: int level = -1;
20358:
20359: if(sio[c].irq_enable & 0x08) {
20360: EnterCriticalSection(&sio_mt[c].csModemStat);
20361: if((sio[c].modem_stat & 0x0f) != 0) {
20362: level = 0;
20363: }
20364: EnterCriticalSection(&sio_mt[c].csModemStat);
20365: }
20366: if(sio[c].irq_enable & 0x02) {
20367: if(sio[c].line_stat_buf & 0x20) {
20368: level = 1;
20369: }
20370: }
20371: if(sio[c].irq_enable & 0x01) {
20372: if(sio[c].line_stat_buf & 0x01) {
20373: level = 2;
20374: }
20375: }
20376: if(sio[c].irq_enable & 0x04) {
20377: EnterCriticalSection(&sio_mt[c].csLineStat);
20378: if(sio[c].line_stat_err != 0) {
20379: level = 3;
20380: }
20381: LeaveCriticalSection(&sio_mt[c].csLineStat);
20382: }
20383:
20384: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
20385: if(level != -1) {
20386: sio[c].irq_identify = level << 1;
20387: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
20388: } else {
20389: sio[c].irq_identify = 1;
20390: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
20391: }
20392: }
20393:
20394: DWORD WINAPI sio_thread(void *lpx)
20395: {
20396: volatile sio_t *p = (sio_t *)lpx;
20397: sio_mt_t *q = &sio_mt[p->channel];
20398:
20399: char name[] = "COM1";
20400: name[3] = '0' + sio_port_number[p->channel];
20401: HANDLE hComm = NULL;
20402: COMMPROP commProp;
20403: DCB dcb;
20404: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
20405: BYTE bytBuffer[SIO_BUFFER_SIZE];
20406:
20407: if((hComm = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
20408: if(GetCommProperties(hComm, &commProp)) {
20409: dwSettableBaud = commProp.dwSettableBaud;
20410: }
20411: EscapeCommFunction(hComm, CLRBREAK);
20412: // EscapeCommFunction(hComm, SETRTS);
20413: // EscapeCommFunction(hComm, SETDTR);
20414:
20415: while(!m_exit) {
20416: // setup comm port
20417: bool comm_state_changed = false;
20418:
20419: EnterCriticalSection(&q->csLineCtrl);
20420: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
20421: p->prev_divisor = p->divisor.w;
20422: p->prev_line_ctrl = p->line_ctrl;
20423: comm_state_changed = true;
20424: }
20425: LeaveCriticalSection(&q->csLineCtrl);
20426:
20427: if(comm_state_changed) {
20428: if(GetCommState(hComm, &dcb)) {
20429: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
20430: DWORD baud = 115200 / p->prev_divisor;
20431: dcb.BaudRate = 9600; // default
20432:
20433: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
20434: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
20435: // 134.5bps is not supported ???
20436: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
20437: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
20438: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
20439: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
20440: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
20441: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
20442: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
20443: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
20444: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
20445: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
20446: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
20447: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
20448: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
20449:
20450: switch(p->prev_line_ctrl & 0x03) {
20451: case 0x00: dcb.ByteSize = 5; break;
20452: case 0x01: dcb.ByteSize = 6; break;
20453: case 0x02: dcb.ByteSize = 7; break;
20454: case 0x03: dcb.ByteSize = 8; break;
20455: }
20456: switch(p->prev_line_ctrl & 0x04) {
20457: case 0x00: dcb.StopBits = ONESTOPBIT; break;
20458: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
20459: }
20460: switch(p->prev_line_ctrl & 0x38) {
20461: case 0x08: dcb.Parity = ODDPARITY; break;
20462: case 0x18: dcb.Parity = EVENPARITY; break;
20463: case 0x28: dcb.Parity = MARKPARITY; break;
20464: case 0x38: dcb.Parity = SPACEPARITY; break;
20465: default: dcb.Parity = NOPARITY; break;
20466: }
20467: dcb.fBinary = TRUE;
20468: dcb.fParity = (dcb.Parity != NOPARITY);
20469: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
20470: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
20471: dcb.fDsrSensitivity = FALSE;//TRUE;
20472: dcb.fTXContinueOnXoff = TRUE;
20473: dcb.fOutX = dcb.fInX = FALSE;
20474: dcb.fErrorChar = FALSE;
20475: dcb.fNull = FALSE;
20476: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
20477: dcb.fAbortOnError = FALSE;
20478:
20479: SetCommState(hComm, &dcb);
20480: }
20481:
20482: // check again to apply all comm state changes
20483: Sleep(10);
20484: continue;
20485: }
20486:
20487: // set comm pins
20488: bool change_brk = false;
20489: // bool change_rts = false;
20490: // bool change_dtr = false;
20491:
20492: EnterCriticalSection(&q->csModemCtrl);
20493: if(p->prev_set_brk != p->set_brk) {
20494: p->prev_set_brk = p->set_brk;
20495: change_brk = true;
20496: }
20497: // if(p->prev_set_rts != p->set_rts) {
20498: // p->prev_set_rts = p->set_rts;
20499: // change_rts = true;
20500: // }
20501: // if(p->prev_set_dtr != p->set_dtr) {
20502: // p->prev_set_dtr = p->set_dtr;
20503: // change_dtr = true;
20504: // }
20505: LeaveCriticalSection(&q->csModemCtrl);
20506:
20507: if(change_brk) {
20508: static UINT32 clear_time = 0;
20509: if(p->prev_set_brk) {
20510: EscapeCommFunction(hComm, SETBREAK);
20511: clear_time = timeGetTime() + 200;
20512: } else {
20513: // keep break for at least 200msec
20514: UINT32 cur_time = timeGetTime();
20515: if(clear_time > cur_time) {
20516: Sleep(clear_time - cur_time);
20517: }
20518: EscapeCommFunction(hComm, CLRBREAK);
20519: }
20520: }
20521: // if(change_rts) {
20522: // if(p->prev_set_rts) {
20523: // EscapeCommFunction(hComm, SETRTS);
20524: // } else {
20525: // EscapeCommFunction(hComm, CLRRTS);
20526: // }
20527: // }
20528: // if(change_dtr) {
20529: // if(p->prev_set_dtr) {
20530: // EscapeCommFunction(hComm, SETDTR);
20531: // } else {
20532: // EscapeCommFunction(hComm, CLRDTR);
20533: // }
20534: // }
20535:
20536: // get comm pins
20537: DWORD dwModemStat = 0;
20538:
20539: if(GetCommModemStatus(hComm, &dwModemStat)) {
20540: EnterCriticalSection(&q->csModemStat);
20541: if(dwModemStat & MS_RLSD_ON) {
20542: p->modem_stat |= 0x80;
20543: } else {
20544: p->modem_stat &= ~0x80;
20545: }
20546: if(dwModemStat & MS_RING_ON) {
20547: p->modem_stat |= 0x40;
20548: } else {
20549: p->modem_stat &= ~0x40;
20550: }
20551: // if(dwModemStat & MS_DSR_ON) {
20552: // p->modem_stat |= 0x20;
20553: // } else {
20554: // p->modem_stat &= ~0x20;
20555: // }
20556: // if(dwModemStat & MS_CTS_ON) {
20557: // p->modem_stat |= 0x10;
20558: // } else {
20559: // p->modem_stat &= ~0x10;
20560: // }
20561: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
20562: p->modem_stat |= 0x08;
20563: }
20564: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
20565: p->modem_stat |= 0x04;
20566: }
20567: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
20568: // p->modem_stat |= 0x02;
20569: // }
20570: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
20571: // p->modem_stat |= 0x01;
20572: // }
20573: LeaveCriticalSection(&q->csModemStat);
20574: }
20575:
20576: // send data
20577: DWORD dwSend = 0;
20578:
20579: EnterCriticalSection(&q->csSendData);
20580: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
20581: bytBuffer[dwSend++] = p->send_buffer->read();
20582: }
20583: LeaveCriticalSection(&q->csSendData);
20584:
20585: if(dwSend != 0) {
20586: DWORD dwWritten = 0;
20587: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
20588: }
20589:
20590: // get line status and recv data
20591: DWORD dwLineStat = 0;
20592: COMSTAT comStat;
20593:
20594: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
20595: EnterCriticalSection(&q->csLineStat);
20596: if(dwLineStat & CE_BREAK) {
20597: p->line_stat_err |= 0x10;
20598: }
20599: if(dwLineStat & CE_FRAME) {
20600: p->line_stat_err |= 0x08;
20601: }
20602: if(dwLineStat & CE_RXPARITY) {
20603: p->line_stat_err |= 0x04;
20604: }
20605: if(dwLineStat & CE_OVERRUN) {
20606: p->line_stat_err |= 0x02;
20607: }
20608: LeaveCriticalSection(&q->csLineStat);
20609:
20610: if(comStat.cbInQue != 0) {
20611: EnterCriticalSection(&q->csRecvData);
20612: DWORD dwRecv = 0;
20613: if(p->recv_buffer != NULL) {
20614: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
20615: }
20616: LeaveCriticalSection(&q->csRecvData);
20617:
20618: if(dwRecv != 0) {
20619: DWORD dwRead = 0;
20620: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
20621: EnterCriticalSection(&q->csRecvData);
20622: if(p->recv_buffer != NULL) {
20623: for(int i = 0; i < dwRead; i++) {
20624: p->recv_buffer->write(bytBuffer[i]);
20625: }
20626: }
20627: LeaveCriticalSection(&q->csRecvData);
20628: }
20629: }
20630: }
20631: }
20632: Sleep(10);
20633: }
20634: CloseHandle(hComm);
20635: }
20636: return 0;
20637: }
20638:
20639: // cmos
20640:
20641: void cmos_init()
20642: {
20643: memset(cmos, 0, sizeof(cmos));
20644: cmos_addr = 0;
20645:
20646: // from DOSBox
20647: cmos_write(0x0a, 0x26);
20648: cmos_write(0x0b, 0x02);
20649: cmos_write(0x0d, 0x80);
20650: }
20651:
20652: void cmos_write(int addr, UINT8 val)
20653: {
20654: cmos[addr & 0x7f] = val;
20655: }
20656:
20657: #define CMOS_GET_TIME() { \
20658: UINT32 cur_sec = timeGetTime() / 1000 ; \
20659: if(prev_sec != cur_sec) { \
20660: GetLocalTime(&time); \
20661: prev_sec = cur_sec; \
20662: } \
20663: }
20664: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
20665:
20666: UINT8 cmos_read(int addr)
20667: {
20668: static SYSTEMTIME time;
20669: static UINT32 prev_sec = 0;
20670:
20671: switch(addr & 0x7f) {
20672: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
20673: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
20674: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
20675: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
20676: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
20677: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
20678: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
20679: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
20680: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
20681: case 0x15: return((MEMORY_END >> 10) & 0xff);
20682: case 0x16: return((MEMORY_END >> 18) & 0xff);
20683: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
20684: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
20685: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
20686: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
20687: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
20688: }
20689: return(cmos[addr & 0x7f]);
20690: }
20691:
20692: // kbd (a20)
20693:
20694: void kbd_init()
20695: {
20696: kbd_data = kbd_command = 0;
20697: kbd_status = 0x18;
20698: }
20699:
20700: UINT8 kbd_read_data()
20701: {
20702: UINT8 data = kbd_data;
20703: kbd_data = 0;
20704: kbd_status &= ~1;
20705: return(data);
20706: }
20707:
20708: void kbd_write_data(UINT8 val)
20709: {
20710: switch(kbd_command) {
20711: case 0xd1:
20712: i386_set_a20_line((val >> 1) & 1);
20713: break;
20714: }
20715: kbd_command = 0;
20716: kbd_status &= ~8;
20717: }
20718:
20719: UINT8 kbd_read_status()
20720: {
20721: return(kbd_status);
20722: }
20723:
20724: void kbd_write_command(UINT8 val)
20725: {
20726: switch(val) {
20727: case 0xd0:
20728: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
20729: kbd_status |= 1;
20730: break;
20731: case 0xdd:
20732: i386_set_a20_line(0);
20733: break;
20734: case 0xdf:
20735: i386_set_a20_line(1);
20736: break;
20737: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
20738: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
20739: if(!(val & 1)) {
20740: if((cmos[0x0f] & 0x7f) == 5) {
20741: // reset pic
20742: pic_init();
20743: pic[0].irr = pic[1].irr = 0x00;
20744: pic[0].imr = pic[1].imr = 0xff;
20745: }
20746: CPU_RESET_CALL(CPU_MODEL);
20747: UINT16 address = *(UINT16 *)(mem + 0x467);
20748: UINT16 selector = *(UINT16 *)(mem + 0x469);
20749: i386_jmp_far(selector, address);
20750: }
20751: i386_set_a20_line((val >> 1) & 1);
20752: break;
20753: }
20754: kbd_command = val;
20755: kbd_status |= 8;
20756: }
20757:
20758: // vga
20759:
20760: UINT8 vga_read_status()
20761: {
20762: // 60hz
20763: static const int period[3] = {16, 17, 17};
20764: static int index = 0;
20765: UINT32 time = timeGetTime() % period[index];
20766:
20767: index = (index + 1) % 3;
20768: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
20769: }
20770:
20771: // i/o bus
20772:
20773: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
20774: //#define SW1US_PATCH
20775:
20776: UINT8 read_io_byte(offs_t addr)
20777: #ifdef USE_DEBUGGER
20778: {
20779: if(now_debugging) {
20780: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
20781: if(in_break_point.table[i].status == 1) {
20782: if(addr == in_break_point.table[i].addr) {
20783: in_break_point.hit = i + 1;
20784: now_suspended = true;
20785: break;
20786: }
20787: }
20788: }
20789: }
20790: return(debugger_read_io_byte(addr));
20791: }
20792: UINT8 debugger_read_io_byte(offs_t addr)
20793: #endif
20794: {
20795: UINT8 val = 0xff;
20796:
20797: switch(addr) {
20798: #ifdef SW1US_PATCH
20799: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
20800: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
20801: val = sio_read(0, addr - 1);
20802: break;
20803: #else
20804: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
20805: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
20806: val = dma_read(0, addr);
20807: break;
20808: #endif
20809: case 0x20: case 0x21:
20810: val = pic_read(0, addr);
20811: break;
20812: case 0x40: case 0x41: case 0x42: case 0x43:
20813: val = pit_read(addr & 0x03);
20814: break;
20815: case 0x60:
20816: val = kbd_read_data();
20817: break;
20818: case 0x61:
20819: val = system_port;
20820: break;
20821: case 0x64:
20822: val = kbd_read_status();
20823: break;
20824: case 0x71:
20825: val = cmos_read(cmos_addr);
20826: break;
20827: case 0x81:
20828: val = dma_page_read(0, 2);
20829: break;
20830: case 0x82:
20831: val = dma_page_read(0, 3);
20832: break;
20833: case 0x83:
20834: val = dma_page_read(0, 1);
20835: break;
20836: case 0x87:
20837: val = dma_page_read(0, 0);
20838: break;
20839: case 0x89:
20840: val = dma_page_read(1, 2);
20841: break;
20842: case 0x8a:
20843: val = dma_page_read(1, 3);
20844: break;
20845: case 0x8b:
20846: val = dma_page_read(1, 1);
20847: break;
20848: case 0x8f:
20849: val = dma_page_read(1, 0);
20850: break;
20851: case 0x92:
20852: val = (m_a20_mask >> 19) & 2;
20853: break;
20854: case 0xa0: case 0xa1:
20855: val = pic_read(1, addr);
20856: break;
20857: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
20858: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
20859: val = dma_read(1, (addr - 0xc0) >> 1);
20860: break;
20861: case 0x278: case 0x279: case 0x27a:
20862: val = pio_read(1, addr);
20863: break;
20864: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
20865: val = sio_read(3, addr);
20866: break;
20867: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
20868: val = sio_read(1, addr);
20869: break;
20870: case 0x378: case 0x379: case 0x37a:
20871: val = pio_read(0, addr);
20872: break;
20873: case 0x3ba: case 0x3da:
20874: val = vga_read_status();
20875: break;
20876: case 0x3bc: case 0x3bd: case 0x3be:
20877: val = pio_read(2, addr);
20878: break;
20879: case 0x3d5:
20880: if(crtc_addr < 16) {
20881: val = crtc_regs[crtc_addr];
20882: }
20883: break;
20884: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
20885: val = sio_read(2, addr);
20886: break;
20887: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
20888: val = sio_read(0, addr);
20889: break;
20890: default:
20891: // fatalerror("unknown inb %4x\n", addr);
20892: break;
20893: }
20894: #ifdef ENABLE_DEBUG_IOPORT
20895: if(fp_debug_log != NULL) {
20896: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
20897: }
20898: #endif
20899: return(val);
20900: }
20901:
20902: UINT16 read_io_word(offs_t addr)
20903: {
20904: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
20905: }
20906:
20907: #ifdef USE_DEBUGGER
20908: UINT16 debugger_read_io_word(offs_t addr)
20909: {
20910: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
20911: }
20912: #endif
20913:
20914: UINT32 read_io_dword(offs_t addr)
20915: {
20916: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
20917: }
20918:
20919: #ifdef USE_DEBUGGER
20920: UINT32 debugger_read_io_dword(offs_t addr)
20921: {
20922: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8) | (debugger_read_io_byte(addr + 2) << 16) | (debugger_read_io_byte(addr + 3) << 24));
20923: }
20924: #endif
20925:
20926: void write_io_byte(offs_t addr, UINT8 val)
20927: #ifdef USE_DEBUGGER
20928: {
20929: if(now_debugging) {
20930: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
20931: if(out_break_point.table[i].status == 1) {
20932: if(addr == out_break_point.table[i].addr) {
20933: out_break_point.hit = i + 1;
20934: now_suspended = true;
20935: break;
20936: }
20937: }
20938: }
20939: }
20940: debugger_write_io_byte(addr, val);
20941: }
20942: void debugger_write_io_byte(offs_t addr, UINT8 val)
20943: #endif
20944: {
20945: #ifdef ENABLE_DEBUG_IOPORT
20946: if(fp_debug_log != NULL) {
20947: #ifdef USE_SERVICE_THREAD
20948: if(addr != 0xf7)
20949: #endif
20950: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
20951: }
20952: #endif
20953: switch(addr) {
20954: #ifdef SW1US_PATCH
20955: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
20956: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
20957: sio_write(0, addr - 1, val);
20958: break;
20959: #else
20960: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
20961: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
20962: dma_write(0, addr, val);
20963: break;
20964: #endif
20965: case 0x20: case 0x21:
20966: pic_write(0, addr, val);
20967: break;
20968: case 0x40: case 0x41: case 0x42: case 0x43:
20969: pit_write(addr & 0x03, val);
20970: break;
20971: case 0x60:
20972: kbd_write_data(val);
20973: break;
20974: case 0x61:
20975: if((system_port & 3) != 3 && (val & 3) == 3) {
20976: // beep on
20977: // MessageBeep(-1);
20978: } else if((system_port & 3) == 3 && (val & 3) != 3) {
20979: // beep off
20980: }
20981: system_port = val;
20982: break;
20983: case 0x64:
20984: kbd_write_command(val);
20985: break;
20986: case 0x70:
20987: cmos_addr = val;
20988: break;
20989: case 0x71:
20990: cmos_write(cmos_addr, val);
20991: break;
20992: case 0x81:
20993: dma_page_write(0, 2, val);
20994: case 0x82:
20995: dma_page_write(0, 3, val);
20996: case 0x83:
20997: dma_page_write(0, 1, val);
20998: case 0x87:
20999: dma_page_write(0, 0, val);
21000: case 0x89:
21001: dma_page_write(1, 2, val);
21002: case 0x8a:
21003: dma_page_write(1, 3, val);
21004: case 0x8b:
21005: dma_page_write(1, 1, val);
21006: case 0x8f:
21007: dma_page_write(1, 0, val);
21008: case 0x92:
21009: i386_set_a20_line((val >> 1) & 1);
21010: break;
21011: case 0xa0: case 0xa1:
21012: pic_write(1, addr, val);
21013: break;
21014: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
21015: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
21016: dma_write(1, (addr - 0xc0) >> 1, val);
21017: break;
21018: #ifdef USE_SERVICE_THREAD
21019: case 0xf7:
21020: // dummy i/o for BIOS/DOS service
21021: if(in_service && cursor_moved) {
21022: // update cursor position before service is done
21023: pcbios_update_cursor_position();
21024: cursor_moved = false;
21025: }
21026: finish_service_loop();
21027: break;
21028: #endif
21029: case 0x278: case 0x279: case 0x27a:
21030: pio_write(1, addr, val);
21031: break;
21032: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
21033: sio_write(3, addr, val);
21034: break;
21035: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
21036: sio_write(1, addr, val);
21037: break;
21038: case 0x378: case 0x379: case 0x37a:
21039: pio_write(0, addr, val);
21040: break;
21041: case 0x3bc: case 0x3bd: case 0x3be:
21042: pio_write(2, addr, val);
21043: break;
21044: case 0x3d4:
21045: crtc_addr = val;
21046: break;
21047: case 0x3d5:
21048: if(crtc_addr < 16) {
21049: if(crtc_regs[crtc_addr] != val) {
21050: crtc_regs[crtc_addr] = val;
21051: crtc_changed[crtc_addr] = 1;
21052: }
21053: }
21054: break;
21055: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
21056: sio_write(2, addr, val);
21057: break;
21058: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
21059: sio_write(0, addr, val);
21060: break;
21061: default:
21062: // fatalerror("unknown outb %4x,%2x\n", addr, val);
21063: break;
21064: }
21065: }
21066:
21067: void write_io_word(offs_t addr, UINT16 val)
21068: {
21069: write_io_byte(addr + 0, (val >> 0) & 0xff);
21070: write_io_byte(addr + 1, (val >> 8) & 0xff);
21071: }
21072:
21073: #ifdef USE_DEBUGGER
21074: void debugger_write_io_word(offs_t addr, UINT16 val)
21075: {
21076: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
21077: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
21078: }
21079: #endif
21080:
21081: void write_io_dword(offs_t addr, UINT32 val)
21082: {
21083: write_io_byte(addr + 0, (val >> 0) & 0xff);
21084: write_io_byte(addr + 1, (val >> 8) & 0xff);
21085: write_io_byte(addr + 2, (val >> 16) & 0xff);
21086: write_io_byte(addr + 3, (val >> 24) & 0xff);
21087: }
21088:
21089: #ifdef USE_DEBUGGER
21090: void debugger_write_io_dword(offs_t addr, UINT32 val)
21091: {
21092: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
21093: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
21094: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
21095: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
21096: }
21097: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.