|
|
1.1 root 1: /*
2: MS-DOS Player for Win32 console
3:
4: Author : Takeda.Toshiya
5: Date : 2009.11.09-
6: */
7:
8: #include "msdos.h"
9:
1.1.1.28 root 10: void exit_handler();
11:
1.1 root 12: #define fatalerror(...) { \
13: fprintf(stderr, __VA_ARGS__); \
1.1.1.28 root 14: exit_handler(); \
1.1 root 15: exit(1); \
16: }
17: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
1.1.1.22 root 18: #define nolog(...)
19:
1.1.1.33 root 20: //#define ENABLE_DEBUG_LOG
21: #ifdef ENABLE_DEBUG_LOG
1.1.1.22 root 22: #define EXPORT_DEBUG_TO_FILE
23: #define ENABLE_DEBUG_SYSCALL
24: #define ENABLE_DEBUG_UNIMPLEMENTED
1.1.1.25 root 25: #define ENABLE_DEBUG_IOPORT
1.1.1.22 root 26:
27: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 28: FILE* fp_debug_log = NULL;
1.1.1.22 root 29: #else
1.1.1.33 root 30: #define fp_debug_log stderr
1.1.1.22 root 31: #endif
32: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
33: #define unimplemented_10h fatalerror
1.1.1.42 root 34: #define unimplemented_13h fatalerror
1.1.1.25 root 35: #define unimplemented_14h fatalerror
1.1.1.22 root 36: #define unimplemented_15h fatalerror
37: #define unimplemented_16h fatalerror
1.1.1.37 root 38: #define unimplemented_17h fatalerror
1.1.1.22 root 39: #define unimplemented_1ah fatalerror
40: #define unimplemented_21h fatalerror
41: #define unimplemented_2fh fatalerror
1.1.1.24 root 42: #define unimplemented_33h fatalerror
1.1.1.22 root 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
1.1.1.42 root 50: #ifndef unimplemented_13h
51: #define unimplemented_13h nolog
52: #endif
1.1.1.25 root 53: #ifndef unimplemented_14h
54: #define unimplemented_14h nolog
55: #endif
1.1.1.22 root 56: #ifndef unimplemented_15h
57: #define unimplemented_15h nolog
58: #endif
59: #ifndef unimplemented_16h
60: #define unimplemented_16h nolog
61: #endif
1.1.1.37 root 62: #ifndef unimplemented_17h
63: #define unimplemented_17h nolog
64: #endif
1.1.1.22 root 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
1.1.1.24 root 74: #ifndef unimplemented_33h
75: #define unimplemented_33h nolog
76: #endif
1.1.1.22 root 77: #ifndef unimplemented_67h
78: #define unimplemented_67h nolog
79: #endif
80: #ifndef unimplemented_xms
81: #define unimplemented_xms nolog
82: #endif
83:
1.1.1.32 root 84: #define array_length(array) (sizeof(array) / sizeof(array[0]))
1.1.1.22 root 85: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
86: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
87: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 88:
1.1.1.12 root 89: #if defined(__MINGW32__)
90: extern "C" int _CRT_glob = 0;
91: #endif
92:
93: /*
94: kludge for "more-standardized" C++
95: */
96: #if !defined(_MSC_VER)
97: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
98: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
99: #define min(a,b) kludge_min(a,b)
100: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 101: #elif _MSC_VER >= 1400
102: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
103: {
104: }
105: #endif
106:
1.1.1.35 root 107: #define USE_VRAM_THREAD
1.1.1.14 root 108:
1.1.1.35 root 109: #ifdef USE_VRAM_THREAD
1.1.1.14 root 110: static CRITICAL_SECTION vram_crit_sect;
111: #else
112: #define vram_flush()
1.1.1.12 root 113: #endif
114:
1.1.1.14 root 115: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
116: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
117:
118: void change_console_size(int width, int height);
119: void clear_scr_buffer(WORD attr);
120:
121: static UINT32 vram_length_char = 0, vram_length_attr = 0;
122: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
123: static COORD vram_coord_char, vram_coord_attr;
124:
1.1.1.28 root 125: char temp_file_path[MAX_PATH];
126: bool temp_file_created = false;
127:
1.1.1.14 root 128: bool ignore_illegal_insn = false;
129: bool limit_max_memory = false;
130: bool no_windows = false;
131: bool stay_busy = false;
1.1.1.19 root 132: bool support_ems = false;
133: #ifdef SUPPORT_XMS
134: bool support_xms = false;
135: #endif
1.1.1.29 root 136: int sio_port_number[4] = {0, 0, 0, 0};
1.1.1.14 root 137:
138: BOOL is_vista_or_later;
139:
1.1.1.35 root 140: #define UPDATE_OPS 16384
141: #define REQUEST_HARDWRE_UPDATE() { \
142: update_ops = UPDATE_OPS - 1; \
143: }
144: UINT32 update_ops = 0;
145: UINT32 idle_ops = 0;
146:
1.1.1.14 root 147: inline void maybe_idle()
148: {
149: // if it appears to be in a tight loop, assume waiting for input
150: // allow for one updated video character, for a spinning cursor
1.1.1.35 root 151: if(!stay_busy && idle_ops < 1024 && vram_length_char <= 1 && vram_length_attr <= 1) {
1.1.1.53! root 152: #if 1
! 153: // YieldProcessor();
! 154: _mm_pause();
! 155: #else
1.1.1.14 root 156: Sleep(10);
1.1.1.35 root 157: REQUEST_HARDWRE_UPDATE();
1.1.1.53! root 158: #endif
1.1.1.14 root 159: }
1.1.1.35 root 160: idle_ops = 0;
1.1.1.14 root 161: }
1.1.1.12 root 162:
1.1 root 163: /* ----------------------------------------------------------------------------
1.1.1.3 root 164: MAME i86/i386
1.1 root 165: ---------------------------------------------------------------------------- */
166:
1.1.1.10 root 167: #ifndef __BIG_ENDIAN__
1.1 root 168: #define LSB_FIRST
1.1.1.10 root 169: #endif
1.1 root 170:
171: #ifndef INLINE
172: #define INLINE inline
173: #endif
174: #define U64(v) UINT64(v)
175:
176: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
177: #define logerror(...)
178: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
179: #define popmessage(...)
180:
181: /*****************************************************************************/
1.1.1.10 root 182: /* src/emu/devcpu.h */
183:
184: // CPU interface functions
185: #define CPU_INIT_NAME(name) cpu_init_##name
186: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
187: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
188:
189: #define CPU_RESET_NAME(name) cpu_reset_##name
190: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
191: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
192:
193: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
194: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
195: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
196:
197: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
198: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
199: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
200:
201: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
202: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
203: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
204:
1.1.1.14 root 205: #define CPU_MODEL_STR(name) #name
206: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
207:
1.1.1.10 root 208: /*****************************************************************************/
209: /* src/emu/didisasm.h */
210:
211: // Disassembler constants
212: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
213: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
214: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
215: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
216: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
217: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
218:
219: /*****************************************************************************/
1.1 root 220: /* src/emu/diexec.h */
221:
222: // I/O line states
223: enum line_state
224: {
225: CLEAR_LINE = 0, // clear (a fired or held) line
226: ASSERT_LINE, // assert an interrupt immediately
227: HOLD_LINE, // hold interrupt line until acknowledged
228: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
229: };
230:
231: // I/O line definitions
232: enum
233: {
234: INPUT_LINE_IRQ = 0,
235: INPUT_LINE_NMI
236: };
237:
238: /*****************************************************************************/
1.1.1.10 root 239: /* src/emu/dimemory.h */
1.1 root 240:
1.1.1.10 root 241: // Translation intentions
242: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
243: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
244: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
245:
246: const int TRANSLATE_READ = 0; // translate for read
247: const int TRANSLATE_WRITE = 1; // translate for write
248: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
249: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
250: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
251: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
252: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
253: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
254: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 255:
1.1.1.10 root 256: /*****************************************************************************/
257: /* src/emu/emucore.h */
1.1 root 258:
1.1.1.10 root 259: // constants for expression endianness
260: enum endianness_t
261: {
262: ENDIANNESS_LITTLE,
263: ENDIANNESS_BIG
264: };
1.1 root 265:
1.1.1.10 root 266: // declare native endianness to be one or the other
267: #ifdef LSB_FIRST
268: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
269: #else
270: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
271: #endif
272:
273: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
274: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
275:
276: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
277: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
278:
279: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
280: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 281:
282: /*****************************************************************************/
283: /* src/emu/memory.h */
284:
1.1.1.10 root 285: // address spaces
286: enum address_spacenum
287: {
288: AS_0, // first address space
289: AS_1, // second address space
290: AS_2, // third address space
291: AS_3, // fourth address space
292: ADDRESS_SPACES, // maximum number of address spaces
293:
294: // alternate address space names for common use
295: AS_PROGRAM = AS_0, // program address space
296: AS_DATA = AS_1, // data address space
297: AS_IO = AS_2 // I/O address space
298: };
299:
1.1 root 300: // offsets and addresses are 32-bit (for now...)
1.1.1.30 root 301: //typedef UINT32 offs_t;
1.1 root 302:
303: // read accessors
304: UINT8 read_byte(offs_t byteaddress)
1.1.1.33 root 305: #ifdef USE_DEBUGGER
306: {
307: if(now_debugging) {
308: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
309: if(rd_break_point.table[i].status == 1) {
310: if(byteaddress == rd_break_point.table[i].addr) {
311: rd_break_point.hit = i + 1;
312: now_suspended = true;
313: break;
314: }
315: }
316: }
317: }
318: return(debugger_read_byte(byteaddress));
319: }
320: UINT8 debugger_read_byte(offs_t byteaddress)
321: #endif
1.1 root 322: {
1.1.1.4 root 323: #if defined(HAS_I386)
1.1 root 324: if(byteaddress < MAX_MEM) {
325: return mem[byteaddress];
1.1.1.3 root 326: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
327: // return read_byte(byteaddress & 0xfffff);
1.1 root 328: }
329: return 0;
1.1.1.4 root 330: #else
331: return mem[byteaddress];
332: #endif
1.1 root 333: }
334:
335: UINT16 read_word(offs_t byteaddress)
1.1.1.33 root 336: #ifdef USE_DEBUGGER
337: {
338: if(now_debugging) {
339: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
340: if(rd_break_point.table[i].status == 1) {
341: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 2) {
342: rd_break_point.hit = i + 1;
343: now_suspended = true;
344: break;
345: }
346: }
347: }
348: }
349: return(debugger_read_word(byteaddress));
350: }
351: UINT16 debugger_read_word(offs_t byteaddress)
352: #endif
1.1 root 353: {
1.1.1.14 root 354: if(byteaddress == 0x41c) {
355: // pointer to first free slot in keyboard buffer
1.1.1.35 root 356: if(key_buf_char != NULL && key_buf_scan != NULL) {
357: #ifdef USE_SERVICE_THREAD
358: EnterCriticalSection(&key_buf_crit_sect);
359: #endif
1.1.1.51 root 360: bool empty = key_buf_char->empty();
1.1.1.35 root 361: #ifdef USE_SERVICE_THREAD
362: LeaveCriticalSection(&key_buf_crit_sect);
363: #endif
1.1.1.51 root 364: if(empty) maybe_idle();
1.1.1.14 root 365: }
366: }
1.1.1.4 root 367: #if defined(HAS_I386)
1.1 root 368: if(byteaddress < MAX_MEM - 1) {
369: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 370: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
371: // return read_word(byteaddress & 0xfffff);
1.1 root 372: }
373: return 0;
1.1.1.4 root 374: #else
375: return *(UINT16 *)(mem + byteaddress);
376: #endif
1.1 root 377: }
378:
379: UINT32 read_dword(offs_t byteaddress)
1.1.1.33 root 380: #ifdef USE_DEBUGGER
381: {
382: if(now_debugging) {
383: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
384: if(rd_break_point.table[i].status == 1) {
385: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 4) {
386: rd_break_point.hit = i + 1;
387: now_suspended = true;
388: break;
389: }
390: }
391: }
392: }
393: return(debugger_read_dword(byteaddress));
394: }
395: UINT32 debugger_read_dword(offs_t byteaddress)
396: #endif
1.1 root 397: {
1.1.1.4 root 398: #if defined(HAS_I386)
1.1 root 399: if(byteaddress < MAX_MEM - 3) {
400: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 401: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
402: // return read_dword(byteaddress & 0xfffff);
1.1 root 403: }
404: return 0;
1.1.1.4 root 405: #else
406: return *(UINT32 *)(mem + byteaddress);
407: #endif
1.1 root 408: }
409:
410: // write accessors
1.1.1.35 root 411: #ifdef USE_VRAM_THREAD
1.1.1.14 root 412: void vram_flush_char()
413: {
414: if(vram_length_char != 0) {
415: DWORD num;
1.1.1.23 root 416: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 417: vram_length_char = vram_last_length_char = 0;
418: }
419: }
420:
421: void vram_flush_attr()
422: {
423: if(vram_length_attr != 0) {
424: DWORD num;
1.1.1.23 root 425: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 426: vram_length_attr = vram_last_length_attr = 0;
427: }
428: }
429:
430: void vram_flush()
431: {
432: if(vram_length_char != 0 || vram_length_attr != 0) {
433: EnterCriticalSection(&vram_crit_sect);
434: vram_flush_char();
435: vram_flush_attr();
436: LeaveCriticalSection(&vram_crit_sect);
437: }
438: }
439: #endif
440:
441: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 442: {
1.1.1.35 root 443: #ifdef USE_VRAM_THREAD
1.1.1.14 root 444: static offs_t first_offset_char, last_offset_char;
445:
446: if(vram_length_char != 0) {
447: if(offset <= last_offset_char && offset >= first_offset_char) {
448: scr_char[(offset - first_offset_char) >> 1] = data;
449: return;
450: }
451: if(offset != last_offset_char + 2) {
452: vram_flush_char();
453: }
454: }
455: if(vram_length_char == 0) {
456: first_offset_char = offset;
457: vram_coord_char.X = (offset >> 1) % scr_width;
458: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
459: }
460: scr_char[vram_length_char++] = data;
461: last_offset_char = offset;
462: #else
1.1.1.8 root 463: COORD co;
464: DWORD num;
465:
1.1.1.14 root 466: co.X = (offset >> 1) % scr_width;
467: co.Y = (offset >> 1) / scr_width;
468: scr_char[0] = data;
1.1.1.23 root 469: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 470: #endif
471: }
472:
473: void write_text_vram_attr(offs_t offset, UINT8 data)
474: {
1.1.1.35 root 475: #ifdef USE_VRAM_THREAD
1.1.1.14 root 476: static offs_t first_offset_attr, last_offset_attr;
477:
478: if(vram_length_attr != 0) {
479: if(offset <= last_offset_attr && offset >= first_offset_attr) {
480: scr_attr[(offset - first_offset_attr) >> 1] = data;
481: return;
482: }
483: if(offset != last_offset_attr + 2) {
484: vram_flush_attr();
485: }
486: }
487: if(vram_length_attr == 0) {
488: first_offset_attr = offset;
489: vram_coord_attr.X = (offset >> 1) % scr_width;
490: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
491: }
492: scr_attr[vram_length_attr++] = data;
493: last_offset_attr = offset;
494: #else
495: COORD co;
496: DWORD num;
1.1.1.8 root 497:
1.1.1.14 root 498: co.X = (offset >> 1) % scr_width;
499: co.Y = (offset >> 1) / scr_width;
500: scr_attr[0] = data;
1.1.1.23 root 501: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 502: #endif
503: }
504:
505: void write_text_vram_byte(offs_t offset, UINT8 data)
506: {
1.1.1.35 root 507: #ifdef USE_VRAM_THREAD
1.1.1.14 root 508: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 509: #endif
1.1.1.8 root 510: if(offset & 1) {
1.1.1.14 root 511: write_text_vram_attr(offset, data);
1.1.1.8 root 512: } else {
1.1.1.14 root 513: write_text_vram_char(offset, data);
1.1.1.8 root 514: }
1.1.1.35 root 515: #ifdef USE_VRAM_THREAD
1.1.1.14 root 516: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 517: #endif
1.1.1.8 root 518: }
519:
520: void write_text_vram_word(offs_t offset, UINT16 data)
521: {
1.1.1.35 root 522: #ifdef USE_VRAM_THREAD
1.1.1.14 root 523: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 524: #endif
1.1.1.8 root 525: if(offset & 1) {
1.1.1.14 root 526: write_text_vram_attr(offset , (data ) & 0xff);
527: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 528: } else {
1.1.1.14 root 529: write_text_vram_char(offset , (data ) & 0xff);
530: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 531: }
1.1.1.35 root 532: #ifdef USE_VRAM_THREAD
1.1.1.14 root 533: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 534: #endif
1.1.1.8 root 535: }
536:
537: void write_text_vram_dword(offs_t offset, UINT32 data)
538: {
1.1.1.35 root 539: #ifdef USE_VRAM_THREAD
1.1.1.14 root 540: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 541: #endif
1.1.1.8 root 542: if(offset & 1) {
1.1.1.14 root 543: write_text_vram_attr(offset , (data ) & 0xff);
544: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
545: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
546: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
547: } else {
548: write_text_vram_char(offset , (data ) & 0xff);
549: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
550: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
551: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 552: }
1.1.1.35 root 553: #ifdef USE_VRAM_THREAD
1.1.1.14 root 554: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 555: #endif
1.1.1.8 root 556: }
557:
1.1 root 558: void write_byte(offs_t byteaddress, UINT8 data)
1.1.1.33 root 559: #ifdef USE_DEBUGGER
560: {
561: if(now_debugging) {
562: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
563: if(wr_break_point.table[i].status == 1) {
564: if(byteaddress == wr_break_point.table[i].addr) {
565: wr_break_point.hit = i + 1;
566: now_suspended = true;
567: break;
568: }
569: }
570: }
571: }
572: debugger_write_byte(byteaddress, data);
573: }
574: void debugger_write_byte(offs_t byteaddress, UINT8 data)
575: #endif
1.1 root 576: {
1.1.1.8 root 577: if(byteaddress < MEMORY_END) {
1.1.1.3 root 578: mem[byteaddress] = data;
1.1.1.8 root 579: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 580: if(!restore_console_on_exit) {
581: change_console_size(scr_width, scr_height);
1.1.1.12 root 582: }
1.1.1.8 root 583: write_text_vram_byte(byteaddress - text_vram_top_address, data);
584: mem[byteaddress] = data;
585: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
586: if(int_10h_feh_called && !int_10h_ffh_called) {
587: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 588: }
589: mem[byteaddress] = data;
1.1.1.4 root 590: #if defined(HAS_I386)
1.1.1.3 root 591: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 592: #else
593: } else {
594: #endif
1.1.1.3 root 595: mem[byteaddress] = data;
1.1 root 596: }
597: }
598:
599: void write_word(offs_t byteaddress, UINT16 data)
1.1.1.33 root 600: #ifdef USE_DEBUGGER
601: {
602: if(now_debugging) {
603: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
604: if(wr_break_point.table[i].status == 1) {
605: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 2) {
606: wr_break_point.hit = i + 1;
607: now_suspended = true;
608: break;
609: }
610: }
611: }
612: }
613: debugger_write_word(byteaddress, data);
614: }
615: void debugger_write_word(offs_t byteaddress, UINT16 data)
616: #endif
1.1 root 617: {
1.1.1.8 root 618: if(byteaddress < MEMORY_END) {
1.1.1.51 root 619: if(byteaddress == cursor_position_address) {
620: if(*(UINT16 *)(mem + byteaddress) != data) {
621: COORD co;
622: co.X = data & 0xff;
623: co.Y = (data >> 8) + scr_top;
624: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
625: }
1.1.1.14 root 626: }
1.1.1.3 root 627: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 628: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 629: if(!restore_console_on_exit) {
630: change_console_size(scr_width, scr_height);
1.1.1.12 root 631: }
1.1.1.8 root 632: write_text_vram_word(byteaddress - text_vram_top_address, data);
633: *(UINT16 *)(mem + byteaddress) = data;
634: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
635: if(int_10h_feh_called && !int_10h_ffh_called) {
636: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 637: }
638: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 639: #if defined(HAS_I386)
1.1.1.3 root 640: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 641: #else
642: } else {
643: #endif
1.1.1.3 root 644: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 645: }
646: }
647:
648: void write_dword(offs_t byteaddress, UINT32 data)
1.1.1.33 root 649: #ifdef USE_DEBUGGER
650: {
651: if(now_debugging) {
652: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
653: if(wr_break_point.table[i].status == 1) {
654: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 4) {
655: wr_break_point.hit = i + 1;
656: now_suspended = true;
657: break;
658: }
659: }
660: }
661: }
662: debugger_write_dword(byteaddress, data);
663: }
664: void debugger_write_dword(offs_t byteaddress, UINT32 data)
665: #endif
1.1 root 666: {
1.1.1.8 root 667: if(byteaddress < MEMORY_END) {
1.1.1.3 root 668: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 669: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 670: if(!restore_console_on_exit) {
671: change_console_size(scr_width, scr_height);
1.1.1.12 root 672: }
1.1.1.8 root 673: write_text_vram_dword(byteaddress - text_vram_top_address, data);
674: *(UINT32 *)(mem + byteaddress) = data;
675: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
676: if(int_10h_feh_called && !int_10h_ffh_called) {
677: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 678: }
679: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 680: #if defined(HAS_I386)
1.1.1.3 root 681: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 682: #else
683: } else {
684: #endif
1.1.1.3 root 685: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 686: }
687: }
688:
689: #define read_decrypted_byte read_byte
690: #define read_decrypted_word read_word
691: #define read_decrypted_dword read_dword
692:
1.1.1.3 root 693: #define read_raw_byte read_byte
694: #define write_raw_byte write_byte
695:
696: #define read_word_unaligned read_word
697: #define write_word_unaligned write_word
698:
699: #define read_io_word_unaligned read_io_word
700: #define write_io_word_unaligned write_io_word
701:
1.1 root 702: UINT8 read_io_byte(offs_t byteaddress);
703: UINT16 read_io_word(offs_t byteaddress);
704: UINT32 read_io_dword(offs_t byteaddress);
705:
706: void write_io_byte(offs_t byteaddress, UINT8 data);
707: void write_io_word(offs_t byteaddress, UINT16 data);
708: void write_io_dword(offs_t byteaddress, UINT32 data);
709:
710: /*****************************************************************************/
711: /* src/osd/osdcomm.h */
712:
713: /* Highly useful macro for compile-time knowledge of an array size */
714: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
715:
1.1.1.3 root 716: #if defined(HAS_I386)
1.1.1.10 root 717: static CPU_TRANSLATE(i386);
718: #include "mame/lib/softfloat/softfloat.c"
719: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 720: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 721: #elif defined(HAS_I286)
1.1.1.10 root 722: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 723: #else
1.1.1.10 root 724: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 725: #endif
1.1.1.33 root 726: #ifdef USE_DEBUGGER
1.1.1.10 root 727: #include "mame/emu/cpu/i386/i386dasm.c"
1.1 root 728: #endif
729:
1.1.1.3 root 730: #if defined(HAS_I386)
731: #define SREG(x) m_sreg[x].selector
732: #define SREG_BASE(x) m_sreg[x].base
733: int cpu_type, cpu_step;
734: #else
735: #define REG8(x) m_regs.b[x]
736: #define REG16(x) m_regs.w[x]
737: #define SREG(x) m_sregs[x]
738: #define SREG_BASE(x) m_base[x]
1.1.1.33 root 739: #define m_eip (m_pc - m_base[CS])
1.1.1.3 root 740: #define m_CF m_CarryVal
741: #define m_a20_mask AMASK
742: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
743: #if defined(HAS_I286)
744: #define i386_set_a20_line(x) i80286_set_a20_line(x)
745: #else
746: #define i386_set_a20_line(x)
747: #endif
748: #define i386_set_irq_line(x, y) set_irq_line(x, y)
749: #endif
1.1 root 750:
751: void i386_jmp_far(UINT16 selector, UINT32 address)
752: {
1.1.1.3 root 753: #if defined(HAS_I386)
1.1 root 754: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 755: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 756: } else {
1.1.1.3 root 757: SREG(CS) = selector;
758: m_performed_intersegment_jump = 1;
759: i386_load_segment_descriptor(CS);
760: m_eip = address;
761: CHANGE_PC(m_eip);
1.1 root 762: }
1.1.1.3 root 763: #elif defined(HAS_I286)
764: i80286_code_descriptor(selector, address, 1);
765: #else
766: SREG(CS) = selector;
767: i386_load_segment_descriptor(CS);
768: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
769: #endif
1.1 root 770: }
771:
1.1.1.24 root 772: void i386_call_far(UINT16 selector, UINT32 address)
773: {
774: #if defined(HAS_I386)
775: if(PROTECTED_MODE && !V8086_MODE) {
776: i386_protected_mode_call(selector, address, 1, m_operand_size);
777: } else {
778: PUSH16(SREG(CS));
779: PUSH16(m_eip);
780: SREG(CS) = selector;
781: m_performed_intersegment_jump = 1;
782: i386_load_segment_descriptor(CS);
783: m_eip = address;
784: CHANGE_PC(m_eip);
785: }
786: #else
787: UINT16 ip = m_pc - SREG_BASE(CS);
788: UINT16 cs = SREG(CS);
789: #if defined(HAS_I286)
790: i80286_code_descriptor(selector, address, 2);
791: #else
792: SREG(CS) = selector;
793: i386_load_segment_descriptor(CS);
794: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
795: #endif
796: PUSH(cs);
797: PUSH(ip);
798: CHANGE_PC(m_pc);
799: #endif
800: }
1.1.1.49 root 801:
802: void i386_push16(UINT16 value)
803: {
804: #if defined(HAS_I386)
805: PUSH16(value);
806: #else
807: PUSH(value);
1.1.1.35 root 808: #endif
1.1.1.49 root 809: }
810:
811: UINT16 i386_pop16()
812: {
813: #if defined(HAS_I386)
814: return POP16();
815: #else
816: UINT16 value;
817: POP(value);
818: return value;
819: #endif
820: }
1.1.1.24 root 821:
1.1.1.29 root 822: UINT16 i386_read_stack()
823: {
824: #if defined(HAS_I386)
825: UINT32 ea, new_esp;
826: if( STACK_32BIT ) {
827: new_esp = REG32(ESP) + 2;
828: ea = i386_translate(SS, new_esp - 2, 0);
829: } else {
830: new_esp = REG16(SP) + 2;
831: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
832: }
833: return READ16(ea);
834: #else
835: UINT16 sp = m_regs.w[SP] + 2;
836: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
837: #endif
838: }
839:
1.1.1.53! root 840: void i386_write_stack(UINT16 value)
! 841: {
! 842: #if defined(HAS_I386)
! 843: UINT32 ea, new_esp;
! 844: if( STACK_32BIT ) {
! 845: new_esp = REG32(ESP) + 2;
! 846: ea = i386_translate(SS, new_esp - 2, 0);
! 847: } else {
! 848: new_esp = REG16(SP) + 2;
! 849: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
! 850: }
! 851: WRITE16(ea, value);
! 852: #else
! 853: UINT16 sp = m_regs.w[SP] + 2;
! 854: WriteWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK), value);
! 855: #endif
! 856: }
! 857:
1.1 root 858: /* ----------------------------------------------------------------------------
1.1.1.33 root 859: debugger
860: ---------------------------------------------------------------------------- */
861:
862: #ifdef USE_DEBUGGER
863: #define TELNET_BLUE 0x0004 // text color contains blue.
864: #define TELNET_GREEN 0x0002 // text color contains green.
865: #define TELNET_RED 0x0001 // text color contains red.
866: #define TELNET_INTENSITY 0x0008 // text color is intensified.
867:
868: int svr_socket = 0;
869: int cli_socket = 0;
870:
1.1.1.52 root 871: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error = true);
1.1.1.33 root 872:
873: void debugger_init()
874: {
875: now_debugging = false;
876: now_going = false;
877: now_suspended = false;
878: force_suspend = false;
879:
880: memset(&break_point, 0, sizeof(break_point_t));
881: memset(&rd_break_point, 0, sizeof(break_point_t));
882: memset(&wr_break_point, 0, sizeof(break_point_t));
883: memset(&in_break_point, 0, sizeof(break_point_t));
884: memset(&out_break_point, 0, sizeof(break_point_t));
885: memset(&int_break_point, 0, sizeof(int_break_point_t));
886: }
887:
1.1.1.45 root 888: void telnet_send(const char *string)
1.1.1.33 root 889: {
890: char buffer[8192], *ptr;
891: strcpy(buffer, string);
892: while((ptr = strstr(buffer, "\n")) != NULL) {
893: char tmp[8192];
894: *ptr = '\0';
895: sprintf(tmp, "%s\033E%s", buffer, ptr + 1);
896: strcpy(buffer, tmp);
897: }
898:
899: int len = strlen(buffer), res;
900: ptr = buffer;
901: while(len > 0) {
902: if((res = send(cli_socket, ptr, len, 0)) > 0) {
903: len -= res;
904: ptr += res;
905: }
906: }
907: }
908:
909: void telnet_command(const char *format, ...)
910: {
911: char buffer[1024];
912: va_list ap;
913: va_start(ap, format);
914: vsprintf(buffer, format, ap);
915: va_end(ap);
916:
917: telnet_send(buffer);
918: }
919:
920: void telnet_printf(const char *format, ...)
921: {
922: char buffer[1024];
923: va_list ap;
924: va_start(ap, format);
925: vsprintf(buffer, format, ap);
926: va_end(ap);
927:
928: if(fp_debugger != NULL) {
929: fprintf(fp_debugger, "%s", buffer);
930: }
931: telnet_send(buffer);
932: }
933:
934: bool telnet_gets(char *str, int n)
935: {
936: char buffer[1024];
937: int ptr = 0;
938:
939: telnet_command("\033[12l"); // local echo on
940: telnet_command("\033[2l"); // key unlock
941:
942: while(!m_halted) {
943: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
944:
945: if(len > 0 && buffer[0] != 0xff) {
946: for(int i = 0; i < len; i++) {
947: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
948: str[ptr] = 0;
949: telnet_command("\033[2h"); // key lock
950: telnet_command("\033[12h"); // local echo off
951: return(!m_halted);
952: } else if(buffer[i] == 0x08) {
953: if(ptr > 0) {
954: telnet_command("\033[0K"); // erase from cursor position
955: ptr--;
956: } else {
957: telnet_command("\033[1C"); // move cursor forward
958: }
959: } else if(ptr < n - 1) {
1.1.1.37 root 960: if(buffer[i] >= 0x20 && buffer[i] <= 0x7e) {
1.1.1.33 root 961: str[ptr++] = buffer[i];
962: }
963: } else {
964: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position
965: }
966: }
967: } else if(len == -1) {
968: if(WSAGetLastError() != WSAEWOULDBLOCK) {
969: return(false);
970: }
971: } else if(len == 0) {
972: return(false);
973: }
974: Sleep(10);
975: }
976: return(!m_halted);
977: }
978:
979: bool telnet_kbhit()
980: {
981: char buffer[1024];
982:
983: if(!m_halted) {
984: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
985:
986: if(len > 0) {
987: for(int i = 0; i < len; i++) {
988: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
989: return(true);
990: }
991: }
992: } else if(len == 0) {
993: return(true); // disconnected
994: }
995: }
996: return(false);
997: }
998:
999: bool telnet_disconnected()
1000: {
1001: char buffer[1024];
1002: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
1003:
1004: if(len == 0) {
1005: return(true);
1006: } else if(len == -1) {
1007: if(WSAGetLastError() != WSAEWOULDBLOCK) {
1008: return(true);
1009: }
1010: }
1011: return(false);
1012: }
1013:
1014: void telnet_set_color(int color)
1015: {
1016: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7));
1017: }
1018:
1019: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip)
1020: {
1021: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1));
1022: UINT8 ops[16];
1023: for(int i = 0; i < 16; i++) {
1024: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK);
1025: }
1026: UINT8 *oprom = ops;
1027:
1028: #if defined(HAS_I386)
1029: if(m_operand_size) {
1030: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK);
1031: } else
1032: #endif
1033: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK);
1034: }
1035:
1036: void debugger_regs_info(char *buffer)
1037: {
1038: #if defined(HAS_I386)
1039: UINT32 flags = get_flags();
1040: #else
1041: UINT32 flags = CompressFlags();
1042: #endif
1043: #if defined(HAS_I386)
1044: if(m_operand_size) {
1045: 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",
1046: 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),
1047: PROTECTED_MODE ? "PE" : "--",
1048: (flags & 0x40000) ? 'A' : '-',
1049: (flags & 0x20000) ? 'V' : '-',
1050: (flags & 0x10000) ? 'R' : '-',
1051: (flags & 0x04000) ? 'N' : '-',
1052: (flags & 0x02000) ? '1' : '0',
1053: (flags & 0x01000) ? '1' : '0',
1054: (flags & 0x00800) ? 'O' : '-',
1055: (flags & 0x00400) ? 'D' : '-',
1056: (flags & 0x00200) ? 'I' : '-',
1057: (flags & 0x00100) ? 'T' : '-',
1058: (flags & 0x00080) ? 'S' : '-',
1059: (flags & 0x00040) ? 'Z' : '-',
1060: (flags & 0x00010) ? 'A' : '-',
1061: (flags & 0x00004) ? 'P' : '-',
1062: (flags & 0x00001) ? 'C' : '-');
1063: } else {
1064: #endif
1065: 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",
1066: 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),
1067: #if defined(HAS_I386)
1068: PROTECTED_MODE ? "PE" : "--",
1069: #else
1070: "--",
1071: #endif
1072: (flags & 0x40000) ? 'A' : '-',
1073: (flags & 0x20000) ? 'V' : '-',
1074: (flags & 0x10000) ? 'R' : '-',
1075: (flags & 0x04000) ? 'N' : '-',
1076: (flags & 0x02000) ? '1' : '0',
1077: (flags & 0x01000) ? '1' : '0',
1078: (flags & 0x00800) ? 'O' : '-',
1079: (flags & 0x00400) ? 'D' : '-',
1080: (flags & 0x00200) ? 'I' : '-',
1081: (flags & 0x00100) ? 'T' : '-',
1082: (flags & 0x00080) ? 'S' : '-',
1083: (flags & 0x00040) ? 'Z' : '-',
1084: (flags & 0x00010) ? 'A' : '-',
1085: (flags & 0x00004) ? 'P' : '-',
1086: (flags & 0x00001) ? 'C' : '-');
1087: #if defined(HAS_I386)
1088: }
1089: #endif
1090: }
1091:
1092: void debugger_process_info(char *buffer)
1093: {
1094: UINT16 psp_seg = current_psp;
1095: process_t *process;
1096: bool check[0x10000] = {0};
1097:
1098: buffer[0] = '\0';
1099:
1100: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) {
1101: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1102: char *file = process->module_path, *s;
1103: char tmp[8192];
1104:
1105: while((s = strstr(file, "\\")) != NULL) {
1106: file = s + 1;
1107: }
1108: 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));
1109: strcat(tmp, buffer);
1110: strcpy(buffer, tmp);
1111:
1112: check[psp_seg] = true;
1113: psp_seg = psp->parent_psp;
1114: }
1115: }
1116:
1117: UINT32 debugger_get_val(const char *str)
1118: {
1119: char tmp[1024];
1120:
1121: if(str == NULL || strlen(str) == 0) {
1122: return(0);
1123: }
1124: strcpy(tmp, str);
1125:
1126: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') {
1127: // ank
1128: return(tmp[1] & 0xff);
1129: } else if(tmp[0] == '%') {
1130: // decimal
1131: return(strtoul(tmp + 1, NULL, 10));
1132: }
1133: return(strtoul(tmp, NULL, 16));
1134: }
1135:
1136: UINT32 debugger_get_seg(const char *str, UINT32 val)
1137: {
1138: char tmp[1024], *s;
1139:
1140: if(str == NULL || strlen(str) == 0) {
1141: return(val);
1142: }
1143: strcpy(tmp, str);
1144:
1145: if((s = strstr(tmp, ":")) != NULL) {
1146: // 0000:0000
1147: *s = '\0';
1148: return(debugger_get_val(tmp));
1149: }
1150: return(val);
1151: }
1152:
1153: UINT32 debugger_get_ofs(const char *str)
1154: {
1155: char tmp[1024], *s;
1156:
1157: if(str == NULL || strlen(str) == 0) {
1158: return(0);
1159: }
1160: strcpy(tmp, str);
1161:
1162: if((s = strstr(tmp, ":")) != NULL) {
1163: // 0000:0000
1164: return(debugger_get_val(s + 1));
1165: }
1166: return(debugger_get_val(tmp));
1167: }
1168:
1169: void debugger_main()
1170: {
1171: telnet_command("\033[20h"); // cr-lf
1172:
1173: force_suspend = true;
1174: now_going = false;
1175: now_debugging = true;
1176: Sleep(100);
1177:
1178: if(!m_halted && !now_suspended) {
1179: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1180: telnet_printf("waiting until cpu is suspended...\n");
1181: }
1182: while(!m_halted && !now_suspended) {
1183: if(telnet_disconnected()) {
1184: break;
1185: }
1186: Sleep(10);
1187: }
1188:
1189: char buffer[8192];
1190:
1191: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1192: debugger_process_info(buffer);
1193: telnet_printf("%s", buffer);
1194: debugger_regs_info(buffer);
1195: telnet_printf("%s", buffer);
1196: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1197: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip);
1198: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1199: debugger_dasm(buffer, SREG(CS), m_eip);
1200: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1201: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1202:
1203: #define MAX_COMMAND_LEN 64
1204:
1205: char command[MAX_COMMAND_LEN + 1];
1206: char prev_command[MAX_COMMAND_LEN + 1] = {0};
1207:
1208: UINT32 data_seg = SREG(DS);
1209: UINT32 data_ofs = 0;
1210: UINT32 dasm_seg = SREG(CS);
1211: UINT32 dasm_ofs = m_eip;
1212:
1213: while(!m_halted) {
1214: telnet_printf("- ");
1215: command[0] = '\0';
1216:
1217: if(fi_debugger != NULL) {
1218: while(command[0] == '\0') {
1219: if(fgets(command, sizeof(command), fi_debugger) == NULL) {
1220: break;
1221: }
1222: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) {
1223: command[strlen(command) - 1] = '\0';
1224: }
1225: }
1226: if(command[0] != '\0') {
1227: telnet_command("%s\n", command);
1228: }
1229: }
1230: if(command[0] == '\0') {
1231: if(!telnet_gets(command, sizeof(command))) {
1232: break;
1233: }
1234: }
1235: if(command[0] == '\0') {
1236: strcpy(command, prev_command);
1237: } else {
1238: strcpy(prev_command, command);
1239: }
1240: if(fp_debugger != NULL) {
1241: fprintf(fp_debugger, "%s\n", command);
1242: }
1243:
1244: if(!m_halted && command[0] != 0) {
1245: char *params[32], *token = NULL;
1246: int num = 0;
1247:
1248: if((token = strtok(command, " ")) != NULL) {
1249: params[num++] = token;
1250: while(num < 32 && (token = strtok(NULL, " ")) != NULL) {
1251: params[num++] = token;
1252: }
1253: }
1254: if(stricmp(params[0], "D") == 0) {
1255: if(num <= 3) {
1256: if(num >= 2) {
1257: data_seg = debugger_get_seg(params[1], data_seg);
1258: data_ofs = debugger_get_ofs(params[1]);
1259: }
1260: UINT32 end_seg = data_seg;
1261: UINT32 end_ofs = data_ofs + 8 * 16 - 1;
1262: if(num == 3) {
1263: end_seg = debugger_get_seg(params[2], data_seg);
1264: end_ofs = debugger_get_ofs(params[2]);
1265: }
1266: UINT64 start_addr = (data_seg << 4) + data_ofs;
1267: UINT64 end_addr = (end_seg << 4) + end_ofs;
1.1.1.37 root 1268: // bool is_sjis = false;
1.1.1.33 root 1269:
1270: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) {
1271: if((addr & 0x0f) == 0) {
1272: if((data_ofs = addr - (data_seg << 4)) > 0xffff) {
1273: data_seg += 0x1000;
1274: data_ofs -= 0x10000;
1275: }
1276: telnet_printf("%06X:%04X ", data_seg, data_ofs);
1277: memset(buffer, 0, sizeof(buffer));
1278: }
1279: if(addr < start_addr || addr > end_addr) {
1280: telnet_printf(" ");
1281: buffer[addr & 0x0f] = ' ';
1282: } else {
1283: UINT8 data = debugger_read_byte(addr & ADDR_MASK);
1284: telnet_printf(" %02X", data);
1.1.1.37 root 1285: // if(is_sjis) {
1.1.1.33 root 1286: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1287: // is_sjis = false;
1.1.1.33 root 1288: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) {
1289: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1290: // is_sjis = true;
1.1.1.33 root 1291: // } else
1292: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) {
1293: buffer[addr & 0x0f] = data;
1294: } else {
1295: buffer[addr & 0x0f] = '.';
1296: }
1297: }
1298: if((addr & 0x0f) == 0x0f) {
1299: telnet_printf(" %s\n", buffer);
1300: }
1301: }
1302: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) {
1303: data_seg += 0x1000;
1304: data_ofs -= 0x10000;
1305: }
1306: prev_command[1] = '\0'; // remove parameters to dump continuously
1307: } else {
1308: telnet_printf("invalid parameter number\n");
1309: }
1310: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) {
1311: if(num >= 3) {
1312: UINT32 seg = debugger_get_seg(params[1], data_seg);
1313: UINT32 ofs = debugger_get_ofs(params[1]);
1314: for(int i = 2, j = 0; i < num; i++, j++) {
1315: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff);
1316: }
1317: } else {
1318: telnet_printf("invalid parameter number\n");
1319: }
1320: } else if(stricmp(params[0], "EW") == 0) {
1321: if(num >= 3) {
1322: UINT32 seg = debugger_get_seg(params[1], data_seg);
1323: UINT32 ofs = debugger_get_ofs(params[1]);
1324: for(int i = 2, j = 0; i < num; i++, j += 2) {
1325: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff);
1326: }
1327: } else {
1328: telnet_printf("invalid parameter number\n");
1329: }
1330: } else if(stricmp(params[0], "ED") == 0) {
1331: if(num >= 3) {
1332: UINT32 seg = debugger_get_seg(params[1], data_seg);
1333: UINT32 ofs = debugger_get_ofs(params[1]);
1334: for(int i = 2, j = 0; i < num; i++, j += 4) {
1335: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]));
1336: }
1337: } else {
1338: telnet_printf("invalid parameter number\n");
1339: }
1340: } else if(stricmp(params[0], "EA") == 0) {
1341: if(num >= 3) {
1342: UINT32 seg = debugger_get_seg(params[1], data_seg);
1343: UINT32 ofs = debugger_get_ofs(params[1]);
1344: strcpy(buffer, prev_command);
1345: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) {
1346: int len = strlen(token);
1347: for(int i = 0; i < len; i++) {
1348: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff);
1349: }
1350: } else {
1351: telnet_printf("invalid parameter\n");
1352: }
1353: } else {
1354: telnet_printf("invalid parameter number\n");
1355: }
1356: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) {
1357: if(num == 2) {
1358: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff);
1359: } else {
1360: telnet_printf("invalid parameter number\n");
1361: }
1362: } else if(stricmp(params[0], "IW") == 0) {
1363: if(num == 2) {
1364: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff);
1365: } else {
1366: telnet_printf("invalid parameter number\n");
1367: }
1368: } else if(stricmp(params[0], "ID") == 0) {
1369: if(num == 2) {
1370: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1])));
1371: } else {
1372: telnet_printf("invalid parameter number\n");
1373: }
1374: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) {
1375: if(num == 3) {
1376: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff);
1377: } else {
1378: telnet_printf("invalid parameter number\n");
1379: }
1380: } else if(stricmp(params[0], "OW") == 0) {
1381: if(num == 3) {
1382: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff);
1383: } else {
1384: telnet_printf("invalid parameter number\n");
1385: }
1386: } else if(stricmp(params[0], "OD") == 0) {
1387: if(num == 3) {
1388: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2]));
1389: } else {
1390: telnet_printf("invalid parameter number\n");
1391: }
1392: } else if(stricmp(params[0], "R") == 0) {
1393: if(num == 1) {
1394: debugger_regs_info(buffer);
1395: telnet_printf("%s", buffer);
1396: } else if(num == 3) {
1397: #if defined(HAS_I386)
1398: if(stricmp(params[1], "EAX") == 0) {
1399: REG32(EAX) = debugger_get_val(params[2]);
1400: } else if(stricmp(params[1], "EBX") == 0) {
1401: REG32(EBX) = debugger_get_val(params[2]);
1402: } else if(stricmp(params[1], "ECX") == 0) {
1403: REG32(ECX) = debugger_get_val(params[2]);
1404: } else if(stricmp(params[1], "EDX") == 0) {
1405: REG32(EDX) = debugger_get_val(params[2]);
1406: } else if(stricmp(params[1], "ESP") == 0) {
1407: REG32(ESP) = debugger_get_val(params[2]);
1408: } else if(stricmp(params[1], "EBP") == 0) {
1409: REG32(EBP) = debugger_get_val(params[2]);
1410: } else if(stricmp(params[1], "ESI") == 0) {
1411: REG32(ESI) = debugger_get_val(params[2]);
1412: } else if(stricmp(params[1], "EDI") == 0) {
1413: REG32(EDI) = debugger_get_val(params[2]);
1414: } else
1415: #endif
1416: if(stricmp(params[1], "AX") == 0) {
1417: REG16(AX) = debugger_get_val(params[2]);
1418: } else if(stricmp(params[1], "BX") == 0) {
1419: REG16(BX) = debugger_get_val(params[2]);
1420: } else if(stricmp(params[1], "CX") == 0) {
1421: REG16(CX) = debugger_get_val(params[2]);
1422: } else if(stricmp(params[1], "DX") == 0) {
1423: REG16(DX) = debugger_get_val(params[2]);
1424: } else if(stricmp(params[1], "SP") == 0) {
1425: REG16(SP) = debugger_get_val(params[2]);
1426: } else if(stricmp(params[1], "BP") == 0) {
1427: REG16(BP) = debugger_get_val(params[2]);
1428: } else if(stricmp(params[1], "SI") == 0) {
1429: REG16(SI) = debugger_get_val(params[2]);
1430: } else if(stricmp(params[1], "DI") == 0) {
1431: REG16(DI) = debugger_get_val(params[2]);
1432: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) {
1433: #if defined(HAS_I386)
1434: if(m_operand_size) {
1435: m_eip = debugger_get_val(params[2]);
1436: } else {
1437: m_eip = debugger_get_val(params[2]) & 0xffff;
1438: }
1439: CHANGE_PC(m_eip);
1440: #else
1441: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK;
1442: CHANGE_PC(m_pc);
1443: #endif
1444: } else if(stricmp(params[1], "AL") == 0) {
1445: REG8(AL) = debugger_get_val(params[2]);
1446: } else if(stricmp(params[1], "AH") == 0) {
1447: REG8(AH) = debugger_get_val(params[2]);
1448: } else if(stricmp(params[1], "BL") == 0) {
1449: REG8(BL) = debugger_get_val(params[2]);
1450: } else if(stricmp(params[1], "BH") == 0) {
1451: REG8(BH) = debugger_get_val(params[2]);
1452: } else if(stricmp(params[1], "CL") == 0) {
1453: REG8(CL) = debugger_get_val(params[2]);
1454: } else if(stricmp(params[1], "CH") == 0) {
1455: REG8(CH) = debugger_get_val(params[2]);
1456: } else if(stricmp(params[1], "DL") == 0) {
1457: REG8(DL) = debugger_get_val(params[2]);
1458: } else if(stricmp(params[1], "DH") == 0) {
1459: REG8(DH) = debugger_get_val(params[2]);
1460: } else {
1461: telnet_printf("unknown register %s\n", params[1]);
1462: }
1463: } else {
1464: telnet_printf("invalid parameter number\n");
1465: }
1466: } else if(_tcsicmp(params[0], "S") == 0) {
1467: if(num >= 4) {
1468: UINT32 cur_seg = debugger_get_seg(params[1], data_seg);
1469: UINT32 cur_ofs = debugger_get_ofs(params[1]);
1470: UINT32 end_seg = debugger_get_seg(params[2], cur_seg);
1471: UINT32 end_ofs = debugger_get_ofs(params[2]);
1472: UINT8 list[32];
1473:
1474: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1475: list[j] = debugger_get_val(params[i]);
1476: }
1477: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) {
1478: bool found = true;
1479: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1480: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) {
1481: found = false;
1482: break;
1483: }
1484: }
1485: if(found) {
1486: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs);
1487: }
1488: if((cur_ofs += 1) > 0xffff) {
1489: cur_seg += 0x1000;
1490: cur_ofs -= 0x10000;
1491: }
1492: }
1493: } else {
1494: telnet_printf("invalid parameter number\n");
1495: }
1496: } else if(stricmp(params[0], "U") == 0) {
1497: if(num <= 3) {
1498: if(num >= 2) {
1499: dasm_seg = debugger_get_seg(params[1], dasm_seg);
1500: dasm_ofs = debugger_get_ofs(params[1]);
1501: }
1502: if(num == 3) {
1503: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg);
1504: UINT32 end_ofs = debugger_get_ofs(params[2]);
1505:
1506: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) {
1507: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1508: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1509: for(int i = 0; i < len; i++) {
1510: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1511: }
1512: for(int i = len; i < 8; i++) {
1513: telnet_printf(" ");
1514: }
1515: telnet_printf(" %s\n", buffer);
1516: if((dasm_ofs += len) > 0xffff) {
1517: dasm_seg += 0x1000;
1518: dasm_ofs -= 0x10000;
1519: }
1520: }
1521: } else {
1522: for(int i = 0; i < 16; i++) {
1523: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1524: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1525: for(int i = 0; i < len; i++) {
1526: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1527: }
1528: for(int i = len; i < 8; i++) {
1529: telnet_printf(" ");
1530: }
1531: telnet_printf(" %s\n", buffer);
1532: if((dasm_ofs += len) > 0xffff) {
1533: dasm_seg += 0x1000;
1534: dasm_ofs -= 0x10000;
1535: }
1536: }
1537: }
1538: prev_command[1] = '\0'; // remove parameters to disassemble continuously
1539: } else {
1540: telnet_printf("invalid parameter number\n");
1541: }
1542: } else if(stricmp(params[0], "H") == 0) {
1543: if(num == 3) {
1544: UINT32 l = debugger_get_val(params[1]);
1545: UINT32 r = debugger_get_val(params[2]);
1546: telnet_printf("%08X %08X\n", l + r, l - r);
1547: } else {
1548: telnet_printf("invalid parameter number\n");
1549: }
1550: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) {
1551: break_point_t *break_point_ptr;
1552: #define GET_BREAK_POINT_PTR() { \
1553: if(params[0][0] == 'R') { \
1554: break_point_ptr = &rd_break_point; \
1555: } else if(params[0][0] == 'W') { \
1556: break_point_ptr = &wr_break_point; \
1557: } else if(params[0][0] == 'I') { \
1558: break_point_ptr = &in_break_point; \
1559: } else if(params[0][0] == 'O') { \
1560: break_point_ptr = &out_break_point; \
1561: } else { \
1562: break_point_ptr = &break_point; \
1563: } \
1564: }
1565: GET_BREAK_POINT_PTR();
1566: if(num == 2) {
1567: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1568: UINT32 ofs = debugger_get_ofs(params[1]);
1569: bool found = false;
1570: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1571: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) {
1572: break_point_ptr->table[i].addr = (seg << 4) + ofs;
1573: break_point_ptr->table[i].seg = seg;
1574: break_point_ptr->table[i].ofs = ofs;
1575: break_point_ptr->table[i].status = 1;
1576: found = true;
1577: }
1578: }
1579: if(!found) {
1580: telnet_printf("too many break points\n");
1581: }
1582: } else {
1583: telnet_printf("invalid parameter number\n");
1584: }
1585: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) {
1586: break_point_t *break_point_ptr;
1587: GET_BREAK_POINT_PTR();
1588: if(num == 2) {
1589: UINT32 addr = debugger_get_val(params[1]);
1590: bool found = false;
1591: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1592: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) {
1593: break_point_ptr->table[i].addr = addr;
1594: break_point_ptr->table[i].status = 1;
1595: found = true;
1596: }
1597: }
1598: if(!found) {
1599: telnet_printf("too many break points\n");
1600: }
1601: } else {
1602: telnet_printf("invalid parameter number\n");
1603: }
1604: } 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) {
1605: break_point_t *break_point_ptr;
1606: GET_BREAK_POINT_PTR();
1607: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1608: memset(break_point_ptr, 0, sizeof(break_point_t));
1609: } else if(num >= 2) {
1610: for(int i = 1; i < num; i++) {
1611: int index = debugger_get_val(params[i]);
1612: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1613: telnet_printf("invalid index %x\n", index);
1614: } else {
1615: break_point_ptr->table[index - 1].addr = 0;
1616: break_point_ptr->table[index - 1].seg = 0;
1617: break_point_ptr->table[index - 1].ofs = 0;
1618: break_point_ptr->table[index - 1].status = 0;
1619: }
1620: }
1621: } else {
1622: telnet_printf("invalid parameter number\n");
1623: }
1624: } 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 ||
1625: 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) {
1626: break_point_t *break_point_ptr;
1627: GET_BREAK_POINT_PTR();
1628: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1629: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1630: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1631: if(break_point_ptr->table[i].status != 0) {
1632: break_point_ptr->table[i].status = enabled ? 1 : -1;
1633: }
1634: }
1635: } else if(num >= 2) {
1636: for(int i = 1; i < num; i++) {
1637: int index = debugger_get_val(params[i]);
1638: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1639: telnet_printf("invalid index %x\n", index);
1640: } else if(break_point_ptr->table[index - 1].status == 0) {
1641: telnet_printf("break point %x is null\n", index);
1642: } else {
1643: break_point_ptr->table[index - 1].status = enabled ? 1 : -1;
1644: }
1645: }
1646: } else {
1647: telnet_printf("invalid parameter number\n");
1648: }
1649: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) {
1650: break_point_t *break_point_ptr;
1651: GET_BREAK_POINT_PTR();
1652: if(num == 1) {
1653: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1654: if(break_point_ptr->table[i].status) {
1655: 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);
1656: }
1657: }
1658: } else {
1659: telnet_printf("invalid parameter number\n");
1660: }
1661: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) {
1662: break_point_t *break_point_ptr;
1663: GET_BREAK_POINT_PTR();
1664: if(num == 1) {
1665: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1666: if(break_point_ptr->table[i].status) {
1667: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr);
1668: }
1669: }
1670: } else {
1671: telnet_printf("invalid parameter number\n");
1672: }
1673: } else if(stricmp(params[0], "INTBP") == 0) {
1674: if(num >= 2 && num <= 4) {
1675: int int_num = debugger_get_val(params[1]);
1676: UINT8 ah = 0, ah_registered = 0;
1677: UINT8 al = 0, al_registered = 0;
1678: if(num >= 3) {
1679: ah = debugger_get_val(params[2]);
1680: ah_registered = 1;
1681: }
1682: if(num == 4) {
1683: al = debugger_get_val(params[3]);
1684: al_registered = 1;
1685: }
1686: bool found = false;
1687: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1688: if(int_break_point.table[i].status == 0 || (
1689: int_break_point.table[i].int_num == int_num &&
1690: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered &&
1691: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) {
1692: int_break_point.table[i].int_num = int_num;
1693: int_break_point.table[i].ah = ah;
1694: int_break_point.table[i].ah_registered = ah_registered;
1695: int_break_point.table[i].al = al;
1696: int_break_point.table[i].al_registered = al_registered;
1697: int_break_point.table[i].status = 1;
1698: found = true;
1699: }
1700: }
1701: if(!found) {
1702: telnet_printf("too many break points\n");
1703: }
1704: } else {
1705: telnet_printf("invalid parameter number\n");
1706: }
1707: } else if(stricmp(params[0], "INTBC") == 0) {
1708: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1709: memset(&int_break_point, 0, sizeof(int_break_point_t));
1710: } else if(num >= 2) {
1711: for(int i = 1; i < num; i++) {
1712: int index = debugger_get_val(params[i]);
1713: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1714: telnet_printf("invalid index %x\n", index);
1715: } else {
1716: int_break_point.table[index - 1].int_num = 0;
1717: int_break_point.table[index - 1].ah = 0;
1718: int_break_point.table[index - 1].ah_registered = 0;
1719: int_break_point.table[index - 1].al = 0;
1720: int_break_point.table[index - 1].al_registered = 0;
1721: int_break_point.table[index - 1].status = 0;
1722: }
1723: }
1724: } else {
1725: telnet_printf("invalid parameter number\n");
1726: }
1727: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) {
1728: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1729: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1730: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1731: if(int_break_point.table[i].status != 0) {
1732: int_break_point.table[i].status = enabled ? 1 : -1;
1733: }
1734: }
1735: } else if(num >= 2) {
1736: for(int i = 1; i < num; i++) {
1737: int index = debugger_get_val(params[i]);
1738: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1739: telnet_printf("invalid index %x\n", index);
1740: } else if(int_break_point.table[index - 1].status == 0) {
1741: telnet_printf("break point %x is null\n", index);
1742: } else {
1743: int_break_point.table[index - 1].status = enabled ? 1 : -1;
1744: }
1745: }
1746: } else {
1747: telnet_printf("invalid parameter number\n");
1748: }
1749: } else if(stricmp(params[0], "INTBL") == 0) {
1750: if(num == 1) {
1751: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1752: if(int_break_point.table[i].status) {
1753: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num);
1754: if(int_break_point.table[i].ah_registered) {
1755: telnet_printf(" %02X", int_break_point.table[i].ah);
1756: }
1757: if(int_break_point.table[i].al_registered) {
1758: telnet_printf(" %02X", int_break_point.table[i].al);
1759: }
1760: telnet_printf("\n");
1761: }
1762: }
1763: } else {
1764: telnet_printf("invalid parameter number\n");
1765: }
1766: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) {
1767: if(num == 1 || num == 2) {
1768: break_point_t break_point_stored;
1769: bool break_points_stored = false;
1770:
1771: if(stricmp(params[0], "P") == 0) {
1772: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1773: memset(&break_point, 0, sizeof(break_point_t));
1774: break_points_stored = true;
1775:
1776: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip);
1777: break_point.table[0].status = 1;
1778: } else if(num >= 2) {
1779: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1780: memset(&break_point, 0, sizeof(break_point_t));
1781: break_points_stored = true;
1782:
1783: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1784: UINT32 ofs = debugger_get_ofs(params[1]);
1785: break_point.table[0].addr = (seg << 4) + ofs;
1786: break_point.table[0].seg = seg;
1787: break_point.table[0].ofs = ofs;
1788: break_point.table[0].status = 1;
1789: }
1790: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1791: now_going = true;
1792: now_suspended = false;
1793:
1794: telnet_command("\033[2l"); // key unlock
1795: while(!m_halted && !now_suspended) {
1796: if(telnet_kbhit()) {
1797: break;
1798: }
1799: Sleep(10);
1800: }
1801: now_going = false;
1802: telnet_command("\033[2h"); // key lock
1803:
1804: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1805: Sleep(100);
1806: if(!m_halted && !now_suspended) {
1807: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1808: telnet_printf("waiting until cpu is suspended...\n");
1809: }
1810: }
1811: while(!m_halted && !now_suspended) {
1812: if(telnet_disconnected()) {
1813: break;
1814: }
1815: Sleep(10);
1816: }
1817: dasm_seg = SREG(CS);
1818: dasm_ofs = m_eip;
1819:
1820: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1821: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1822: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1823:
1824: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1825: debugger_regs_info(buffer);
1826: telnet_printf("%s", buffer);
1827:
1828: if(break_point.hit) {
1829: if(stricmp(params[0], "G") == 0 && num == 1) {
1830: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1831: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1832: }
1833: } else if(rd_break_point.hit) {
1834: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1835: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1836: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1837: m_prev_cs, m_prev_eip);
1838: } else if(wr_break_point.hit) {
1839: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1840: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1841: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1842: m_prev_cs, m_prev_eip);
1843: } else if(in_break_point.hit) {
1844: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1845: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1846: in_break_point.table[in_break_point.hit - 1].addr,
1847: m_prev_cs, m_prev_eip);
1848: } else if(out_break_point.hit) {
1849: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1850: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1851: out_break_point.table[out_break_point.hit - 1].addr,
1852: m_prev_cs, m_prev_eip);
1853: } else if(int_break_point.hit) {
1854: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1855: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1856: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1857: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1858: }
1859: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1860: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1861: }
1862: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1863: } else {
1864: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1865: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1866: }
1867: if(break_points_stored) {
1868: memcpy(&break_point, &break_point_stored, sizeof(break_point_t));
1869: }
1870: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1871: debugger_dasm(buffer, SREG(CS), m_eip);
1872: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1873: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1874: } else {
1875: telnet_printf("invalid parameter number\n");
1876: }
1877: } else if(stricmp(params[0], "T") == 0) {
1878: if(num == 1 || num == 2) {
1879: int steps = 1;
1880: if(num >= 2) {
1881: steps = debugger_get_val(params[1]);
1882: }
1883:
1884: telnet_command("\033[2l"); // key unlock
1885: while(steps-- > 0) {
1886: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1887: now_going = false;
1888: now_suspended = false;
1889:
1890: while(!m_halted && !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 || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit || telnet_kbhit()) {
1908: break;
1909: }
1910: }
1911: telnet_command("\033[2h"); // key lock
1912:
1913: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1914: Sleep(100);
1915: if(!m_halted && !now_suspended) {
1916: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1917: telnet_printf("waiting until cpu is suspended...\n");
1918: }
1919: }
1920: while(!m_halted && !now_suspended) {
1921: if(telnet_disconnected()) {
1922: break;
1923: }
1924: Sleep(10);
1925: }
1926: if(break_point.hit) {
1927: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1928: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1929: } else if(rd_break_point.hit) {
1930: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1931: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1932: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1933: m_prev_cs, m_prev_eip);
1934: } else if(wr_break_point.hit) {
1935: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1936: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1937: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1938: m_prev_cs, m_prev_eip);
1939: } else if(in_break_point.hit) {
1940: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1941: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1942: in_break_point.table[in_break_point.hit - 1].addr,
1943: m_prev_cs, m_prev_eip);
1944: } else if(out_break_point.hit) {
1945: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1946: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1947: out_break_point.table[out_break_point.hit - 1].addr,
1948: m_prev_cs, m_prev_eip);
1949: } else if(int_break_point.hit) {
1950: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1951: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1952: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1953: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1954: }
1955: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1956: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1957: }
1958: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1959: } else if(steps > 0) {
1960: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1961: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1962: }
1963: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1964: debugger_dasm(buffer, SREG(CS), m_eip);
1965: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1966: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1967: } else {
1968: telnet_printf("invalid parameter number\n");
1969: }
1970: } else if(stricmp(params[0], "Q") == 0) {
1971: break;
1972: } else if(stricmp(params[0], "X") == 0) {
1973: debugger_process_info(buffer);
1974: telnet_printf("%s", buffer);
1975: } else if(stricmp(params[0], ">") == 0) {
1976: if(num == 2) {
1977: if(fp_debugger != NULL) {
1978: fclose(fp_debugger);
1979: fp_debugger = NULL;
1980: }
1981: fp_debugger = fopen(params[1], "w");
1982: } else {
1983: telnet_printf("invalid parameter number\n");
1984: }
1985: } else if(stricmp(params[0], "<") == 0) {
1986: if(num == 2) {
1987: if(fi_debugger != NULL) {
1988: fclose(fi_debugger);
1989: fi_debugger = NULL;
1990: }
1991: fi_debugger = fopen(params[1], "r");
1992: } else {
1993: telnet_printf("invalid parameter number\n");
1994: }
1995: } else if(stricmp(params[0], "?") == 0) {
1996: telnet_printf("D [<start> [<end>]] - dump memory\n");
1997: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n");
1998: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n");
1999: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n");
2000: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n");
2001:
2002: telnet_printf("R - show registers\n");
2003: telnet_printf("R <reg> <value> - edit register\n");
2004: telnet_printf("S <start> <end> <list> - search\n");
2005: telnet_printf("U [<start> [<end>]] - unassemble\n");
2006:
2007: telnet_printf("H <value> <value> - hexadd\n");
2008:
2009: telnet_printf("BP <address> - set breakpoint\n");
2010: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n");
2011: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n");
2012: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n");
2013: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n");
2014: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n");
2015:
2016: telnet_printf("G - go (press enter key to break)\n");
2017: telnet_printf("G <address> - go and break at address\n");
2018: telnet_printf("P - trace one opcode (step over)\n");
2019: telnet_printf("T [<count>] - trace (step in)\n");
2020: telnet_printf("Q - quit\n");
2021: telnet_printf("X - show dos process info\n");
2022:
2023: telnet_printf("> <filename> - output logfile\n");
2024: telnet_printf("< <filename> - input commands from file\n");
2025:
2026: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n");
2027: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n");
2028: } else {
2029: telnet_printf("unknown command %s\n", params[0]);
2030: }
2031: }
2032: }
2033: if(fp_debugger != NULL) {
2034: fclose(fp_debugger);
2035: fp_debugger = NULL;
2036: }
2037: if(fi_debugger != NULL) {
2038: fclose(fi_debugger);
2039: fi_debugger = NULL;
2040: }
2041: now_debugging = now_going = now_suspended = force_suspend = false;
2042: closesocket(cli_socket);
2043: }
2044:
2045: const char *debugger_get_ttermpro_path()
2046: {
2047: static char path[MAX_PATH] = {0};
2048:
2049: if(getenv("ProgramFiles")) {
2050: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles"));
2051: }
2052: return(path);
2053: }
2054:
2055: const char *debugger_get_ttermpro_x86_path()
2056: {
2057: static char path[MAX_PATH] = {0};
2058:
2059: if(getenv("ProgramFiles(x86)")) {
2060: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)"));
2061: }
2062: return(path);
2063: }
2064:
2065: const char *debugger_get_putty_path()
2066: {
2067: static char path[MAX_PATH] = {0};
2068:
2069: if(getenv("ProgramFiles")) {
2070: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles"));
2071: }
2072: return(path);
2073: }
2074:
2075: const char *debugger_get_putty_x86_path()
2076: {
2077: static char path[MAX_PATH] = {0};
2078:
2079: if(getenv("ProgramFiles(x86)")) {
2080: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)"));
2081: }
2082: return(path);
2083: }
2084:
2085: const char *debugger_get_telnet_path()
2086: {
2087: // NOTE: When you run 32bit version of msdos.exe on Windows x64,
2088: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64.
2089: // But 32bit version of telnet.exe will not be installed in SysWOW64
2090: // and 64bit version of telnet.exe will be installed in System32.
2091: static char path[MAX_PATH] = {0};
2092:
2093: if(getenv("windir") != NULL) {
2094: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir"));
2095: }
2096: return(path);
2097: }
2098:
2099: DWORD WINAPI debugger_thread(LPVOID)
2100: {
2101: WSADATA was_data;
2102: struct sockaddr_in svr_addr;
2103: struct sockaddr_in cli_addr;
2104: int cli_addr_len = sizeof(cli_addr);
2105: int port = 23;
2106: int bind_stat = SOCKET_ERROR;
2107: struct timeval timeout;
2108:
2109: WSAStartup(MAKEWORD(2,0), &was_data);
2110:
2111: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
2112: memset(&svr_addr, 0, sizeof(svr_addr));
2113: svr_addr.sin_family = AF_INET;
2114: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
2115:
2116: while(!m_halted && port < 10000) {
2117: svr_addr.sin_port = htons(port);
2118: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
2119: break;
2120: } else {
2121: port = (port == 23) ? 9000 : (port + 1);
2122: }
2123: }
2124: if(bind_stat == 0) {
2125: timeout.tv_sec = 1;
2126: timeout.tv_usec = 0;
1.1.1.45 root 2127: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
1.1.1.33 root 2128:
2129: listen(svr_socket, 1);
2130:
2131: char command[MAX_PATH] = {0};
2132: STARTUPINFO si;
2133: PROCESS_INFORMATION pi;
2134:
2135: if(_access(debugger_get_ttermpro_path(), 0) == 0) {
2136: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port);
2137: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) {
2138: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port);
2139: } else if(_access(debugger_get_putty_path(), 0) == 0) {
2140: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port);
2141: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) {
2142: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port);
2143: } else if(_access(debugger_get_telnet_path(), 0) == 0) {
2144: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port);
2145: }
2146: if(command[0] != '\0') {
2147: memset(&si, 0, sizeof(STARTUPINFO));
2148: memset(&pi, 0, sizeof(PROCESS_INFORMATION));
2149: CreateProcess(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
2150: }
2151:
2152: while(!m_halted) {
2153: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
2154: u_long val = 1;
2155: ioctlsocket(cli_socket, FIONBIO, &val);
2156: debugger_main();
2157: }
2158: }
2159: }
2160: }
2161: WSACleanup();
2162: return(0);
2163: }
2164: #endif
2165:
2166: /* ----------------------------------------------------------------------------
1.1 root 2167: main
2168: ---------------------------------------------------------------------------- */
2169:
1.1.1.28 root 2170: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
2171: {
2172: if(dwCtrlType == CTRL_BREAK_EVENT) {
1.1.1.33 root 2173: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 2174: #ifdef USE_SERVICE_THREAD
2175: EnterCriticalSection(&key_buf_crit_sect);
2176: #endif
1.1.1.51 root 2177: pcbios_clear_key_buffer();
1.1.1.35 root 2178: #ifdef USE_SERVICE_THREAD
2179: LeaveCriticalSection(&key_buf_crit_sect);
2180: #endif
1.1.1.33 root 2181: }
2182: // key_code = key_recv = 0;
1.1.1.28 root 2183: return TRUE;
2184: } else if(dwCtrlType == CTRL_C_EVENT) {
2185: return TRUE;
2186: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
2187: // this program will be terminated abnormally, do minimum end process
2188: exit_handler();
2189: exit(1);
2190: }
2191: return FALSE;
2192: }
2193:
2194: void exit_handler()
2195: {
2196: if(temp_file_created) {
2197: DeleteFile(temp_file_path);
2198: temp_file_created = false;
2199: }
2200: if(key_buf_char != NULL) {
2201: key_buf_char->release();
2202: delete key_buf_char;
2203: key_buf_char = NULL;
2204: }
2205: if(key_buf_scan != NULL) {
2206: key_buf_scan->release();
2207: delete key_buf_scan;
2208: key_buf_scan = NULL;
2209: }
1.1.1.32 root 2210: #ifdef SUPPORT_XMS
2211: msdos_xms_release();
2212: #endif
1.1.1.28 root 2213: hardware_release();
2214: }
2215:
1.1.1.35 root 2216: #ifdef USE_VRAM_THREAD
1.1.1.28 root 2217: DWORD WINAPI vram_thread(LPVOID)
2218: {
2219: while(!m_halted) {
2220: EnterCriticalSection(&vram_crit_sect);
2221: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
2222: vram_flush_char();
2223: }
2224: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
2225: vram_flush_attr();
2226: }
2227: vram_last_length_char = vram_length_char;
2228: vram_last_length_attr = vram_length_attr;
2229: LeaveCriticalSection(&vram_crit_sect);
2230: // this is about half the maximum keyboard repeat rate - any
2231: // lower tends to be jerky, any higher misses updates
2232: Sleep(15);
2233: }
2234: return 0;
2235: }
2236: #endif
2237:
1.1.1.45 root 2238: long get_section_in_exec_file(FILE *fp, const char *name)
1.1.1.28 root 2239: {
2240: UINT8 header[0x400];
2241:
2242: long position = ftell(fp);
2243: fseek(fp, 0, SEEK_SET);
2244: fread(header, sizeof(header), 1, fp);
2245: fseek(fp, position, SEEK_SET);
2246:
2247: try {
2248: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2249: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2250: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2251: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2252: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2253: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2254:
2255: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
2256: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
2257: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
2258: return(sectionHeader->PointerToRawData);
2259: }
2260: }
2261: } catch(...) {
2262: }
2263: return(0);
2264: }
2265:
1.1.1.10 root 2266: bool is_started_from_command_prompt()
2267: {
1.1.1.18 root 2268: bool ret = false;
2269:
2270: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
2271: if(hLibrary) {
2272: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
2273: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
2274: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
2275: if(lpfnGetConsoleProcessList) {
2276: DWORD pl;
2277: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
2278: FreeLibrary(hLibrary);
2279: return(ret);
2280: }
2281: FreeLibrary(hLibrary);
2282: }
2283:
2284: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2285: if(hSnapshot != INVALID_HANDLE_VALUE) {
2286: DWORD dwParentProcessID = 0;
2287: PROCESSENTRY32 pe32;
2288: pe32.dwSize = sizeof(PROCESSENTRY32);
2289: if(Process32First(hSnapshot, &pe32)) {
2290: do {
2291: if(pe32.th32ProcessID == GetCurrentProcessId()) {
2292: dwParentProcessID = pe32.th32ParentProcessID;
2293: break;
2294: }
2295: } while(Process32Next(hSnapshot, &pe32));
2296: }
2297: CloseHandle(hSnapshot);
2298: if(dwParentProcessID != 0) {
2299: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
2300: if(hProcess != NULL) {
2301: HMODULE hMod;
2302: DWORD cbNeeded;
2303: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
2304: char module_name[MAX_PATH];
2305: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
2306: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
2307: }
2308: }
2309: CloseHandle(hProcess);
2310: }
2311: }
2312: }
2313: return(ret);
1.1.1.14 root 2314: }
2315:
2316: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
2317: {
1.1.1.24 root 2318: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 2319: OSVERSIONINFOEX osvi;
2320: DWORDLONG dwlConditionMask = 0;
2321: int op = VER_GREATER_EQUAL;
2322:
2323: // Initialize the OSVERSIONINFOEX structure.
2324: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
2325: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
2326: osvi.dwMajorVersion = dwMajorVersion;
2327: osvi.dwMinorVersion = dwMinorVersion;
2328: osvi.wServicePackMajor = wServicePackMajor;
2329: osvi.wServicePackMinor = wServicePackMinor;
2330:
2331: // Initialize the condition mask.
2332: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
2333: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
2334: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
2335: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
2336:
2337: // Perform the test.
2338: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
2339: }
2340:
1.1.1.27 root 2341: void get_sio_port_numbers()
2342: {
2343: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
2344: HDEVINFO hDevInfo = 0;
2345: HKEY hKey = 0;
2346: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
2347: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
2348: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
2349: char chData[256];
2350: DWORD dwType = 0;
2351: DWORD dwSize = sizeof(chData);
2352: int port_number = 0;
2353:
2354: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
2355: if(_strnicmp(chData, "COM", 3) == 0) {
2356: port_number = atoi(chData + 3);
2357: }
2358: }
2359: RegCloseKey(hKey);
2360:
1.1.1.29 root 2361: if(sio_port_number[0] == port_number || sio_port_number[1] == port_number || sio_port_number[2] == port_number || sio_port_number[3] == port_number) {
1.1.1.27 root 2362: continue;
2363: }
2364: if(sio_port_number[0] == 0) {
2365: sio_port_number[0] = port_number;
2366: } else if(sio_port_number[1] == 0) {
2367: sio_port_number[1] = port_number;
1.1.1.29 root 2368: } else if(sio_port_number[2] == 0) {
2369: sio_port_number[2] = port_number;
2370: } else if(sio_port_number[3] == 0) {
2371: sio_port_number[3] = port_number;
1.1.1.27 root 2372: }
1.1.1.29 root 2373: if(sio_port_number[0] != 0 && sio_port_number[1] != 0 && sio_port_number[2] != 0 && sio_port_number[3] != 0) {
1.1.1.27 root 2374: break;
2375: }
2376: }
2377: }
2378: }
2379: }
2380:
1.1.1.28 root 2381: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
2382:
1.1 root 2383: int main(int argc, char *argv[], char *envp[])
2384: {
1.1.1.9 root 2385: int arg_offset = 0;
2386: int standard_env = 0;
1.1.1.14 root 2387: int buf_width = 0, buf_height = 0;
1.1.1.28 root 2388: bool get_console_info_success = false;
2389: bool screen_size_changed = false;
2390:
2391: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
2392: GetModuleFileName(NULL, path, MAX_PATH);
2393: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 2394:
1.1.1.27 root 2395: char dummy_argv_0[] = "msdos.exe";
2396: char dummy_argv_1[MAX_PATH];
2397: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
2398: char new_exec_file[MAX_PATH];
2399: bool convert_cmd_file = false;
1.1.1.28 root 2400: unsigned int code_page = 0;
1.1.1.27 root 2401:
2402: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 2403: // check if command file is embedded to this execution file
2404: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 2405: FILE* fp = fopen(full, "rb");
1.1.1.28 root 2406: long offset = get_section_in_exec_file(fp, ".msdos");
2407: if(offset != 0) {
1.1.1.30 root 2408: UINT8 buffer[16];
1.1.1.28 root 2409: fseek(fp, offset, SEEK_SET);
2410: fread(buffer, sizeof(buffer), 1, fp);
2411:
2412: // restore flags
2413: stay_busy = ((buffer[0] & 0x01) != 0);
2414: no_windows = ((buffer[0] & 0x02) != 0);
2415: standard_env = ((buffer[0] & 0x04) != 0);
2416: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
2417: limit_max_memory = ((buffer[0] & 0x10) != 0);
2418: if((buffer[0] & 0x20) != 0) {
2419: get_sio_port_numbers();
2420: }
2421: if((buffer[0] & 0x40) != 0) {
2422: UMB_TOP = EMS_TOP + EMS_SIZE;
2423: support_ems = true;
1.1.1.30 root 2424: }
1.1.1.27 root 2425: #ifdef SUPPORT_XMS
1.1.1.30 root 2426: if((buffer[0] & 0x80) != 0) {
1.1.1.28 root 2427: support_xms = true;
2428: }
1.1.1.30 root 2429: #endif
1.1.1.28 root 2430: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
2431: buf_width = buffer[1] | (buffer[2] << 8);
2432: buf_height = buffer[3] | (buffer[4] << 8);
2433: }
2434: if(buffer[5] != 0) {
1.1.1.30 root 2435: dos_major_version = buffer[5];
2436: dos_minor_version = buffer[6];
2437: }
2438: if(buffer[7] != 0) {
2439: win_major_version = buffer[7];
2440: win_minor_version = buffer[8];
1.1.1.28 root 2441: }
1.1.1.30 root 2442: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
1.1.1.28 root 2443: SetConsoleCP(code_page);
2444: SetConsoleOutputCP(code_page);
2445: }
1.1.1.30 root 2446: int name_len = buffer[11];
2447: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
1.1.1.28 root 2448:
2449: // restore command file name
2450: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
2451: fread(dummy_argv_1, name_len, 1, fp);
2452:
2453: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
2454: // if original command file exists, create a temporary file name
2455: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
2456: // create a temporary command file in the current director
2457: DeleteFile(dummy_argv_1);
1.1.1.27 root 2458: } else {
1.1.1.28 root 2459: // create a temporary command file in the temporary folder
2460: GetTempPath(MAX_PATH, path);
2461: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
2462: DeleteFile(dummy_argv_1);
2463: } else {
2464: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
2465: }
1.1.1.27 root 2466: }
1.1.1.28 root 2467: // check the command file type
2468: fread(buffer, 2, 1, fp);
2469: fseek(fp, -2, SEEK_CUR);
2470: if(memcmp(buffer, "MZ", 2) != 0) {
2471: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
2472: } else {
2473: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 2474: }
2475: }
1.1.1.28 root 2476:
2477: // restore command file
2478: FILE* fo = fopen(dummy_argv_1, "wb");
2479: for(int i = 0; i < file_len; i++) {
2480: fputc(fgetc(fp), fo);
2481: }
2482: fclose(fo);
2483:
2484: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
2485: temp_file_created = true;
2486: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
2487:
2488: // adjust argc/argv
2489: for(int i = 1; i < argc && (i + 1) < 256; i++) {
2490: dummy_argv[i + 1] = argv[i];
2491: }
2492: argc++;
2493: argv = dummy_argv;
1.1.1.27 root 2494: }
2495: fclose(fp);
2496: }
1.1.1.9 root 2497: for(int i = 1; i < argc; i++) {
1.1.1.25 root 2498: if(_strnicmp(argv[i], "-b", 2) == 0) {
2499: stay_busy = true;
2500: arg_offset++;
1.1.1.27 root 2501: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
2502: if(argv[i][2] != '\0') {
2503: strcpy(new_exec_file, &argv[i][2]);
2504: } else {
2505: strcpy(new_exec_file, "new_exec_file.exe");
2506: }
2507: convert_cmd_file = true;
2508: arg_offset++;
1.1.1.28 root 2509: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
2510: if(IS_NUMERIC(argv[i][2])) {
2511: code_page = atoi(&argv[i][2]);
2512: } else {
2513: code_page = GetConsoleCP();
2514: }
2515: arg_offset++;
1.1.1.25 root 2516: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
2517: no_windows = true;
2518: arg_offset++;
2519: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 2520: standard_env = 1;
2521: arg_offset++;
1.1.1.14 root 2522: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
2523: ignore_illegal_insn = true;
2524: arg_offset++;
2525: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
2526: limit_max_memory = true;
2527: arg_offset++;
2528: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.51 root 2529: int result = sscanf(argv[i] + 2, "%d,%d", &buf_height, &buf_width);
2530: if(result == 1) {
2531: buf_width = 0;
2532: } else if(result != 2) {
1.1.1.17 root 2533: buf_width = buf_height = 0;
2534: }
2535: if(buf_width <= 0 || buf_width > 0x7fff) {
2536: buf_width = 80;
2537: }
2538: if(buf_height <= 0 || buf_height > 0x7fff) {
2539: buf_height = 25;
2540: }
1.1.1.14 root 2541: arg_offset++;
1.1.1.25 root 2542: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 2543: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29 root 2544: char *p0 = &argv[i][2], *p1, *p2, *p3;
2545: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
2546: sio_port_number[1] = atoi(p1 + 1);
2547: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
2548: sio_port_number[2] = atoi(p2 + 1);
2549: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
2550: sio_port_number[3] = atoi(p3 + 1);
2551: }
2552: }
1.1.1.25 root 2553: }
1.1.1.29 root 2554: sio_port_number[0] = atoi(p0);
1.1.1.25 root 2555: }
1.1.1.29 root 2556: if(sio_port_number[0] == 0 || sio_port_number[1] == 0 || sio_port_number[2] == 0 || sio_port_number[3] == 0) {
1.1.1.27 root 2557: get_sio_port_numbers();
1.1.1.25 root 2558: }
2559: arg_offset++;
1.1.1.9 root 2560: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 2561: if(strlen(argv[i]) >= 5 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && (argv[i][5] == '\0' || IS_NUMERIC(argv[i][5]))) {
1.1.1.30 root 2562: dos_major_version = argv[i][2] - '0';
2563: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2564: }
2565: arg_offset++;
2566: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
2567: 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]))) {
2568: win_major_version = argv[i][2] - '0';
2569: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 2570: }
2571: arg_offset++;
1.1.1.25 root 2572: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
2573: UMB_TOP = EMS_TOP + EMS_SIZE;
2574: support_ems = true;
2575: #ifdef SUPPORT_XMS
2576: support_xms = true;
2577: #endif
2578: arg_offset++;
1.1.1.9 root 2579: } else {
2580: break;
2581: }
2582: }
2583: if(argc < 2 + arg_offset) {
1.1 root 2584: #ifdef _WIN64
1.1.1.14 root 2585: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 2586: #else
1.1.1.14 root 2587: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 2588: #endif
1.1.1.25 root 2589: fprintf(stderr,
1.1.1.28 root 2590: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.30 root 2591: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
1.1.1.25 root 2592: "\n"
2593: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 2594: #ifdef _WIN64
1.1.1.27 root 2595: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 2596: #else
1.1.1.27 root 2597: "\t-c\tconvert command file to 32bit execution file\n"
2598: #endif
1.1.1.28 root 2599: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 2600: "\t-d\tpretend running under straight DOS, not Windows\n"
2601: "\t-e\tuse a reduced environment block\n"
2602: "\t-i\tignore invalid instructions\n"
2603: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
2604: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
2605: "\t-s\tenable serial I/O and set host's COM port numbers\n"
2606: "\t-v\tset the DOS version\n"
1.1.1.30 root 2607: "\t-w\tset the Windows version\n"
1.1.1.19 root 2608: #ifdef SUPPORT_XMS
1.1.1.28 root 2609: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 2610: #else
1.1.1.28 root 2611: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 2612: #endif
2613: );
1.1.1.10 root 2614:
2615: if(!is_started_from_command_prompt()) {
2616: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
2617: while(!_kbhit()) {
2618: Sleep(10);
2619: }
2620: }
1.1.1.20 root 2621: #ifdef _DEBUG
2622: _CrtDumpMemoryLeaks();
2623: #endif
1.1 root 2624: return(EXIT_FAILURE);
2625: }
1.1.1.27 root 2626: if(convert_cmd_file) {
2627: retval = EXIT_FAILURE;
1.1.1.28 root 2628: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 2629: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 2630: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 2631:
1.1.1.28 root 2632: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
2633: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
2634: } else if((fp = fopen(full, "rb")) == NULL) {
2635: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 2636: } else {
1.1.1.28 root 2637: long offset = get_section_in_exec_file(fp, ".msdos");
2638: if(offset != 0) {
2639: UINT8 buffer[14];
2640: fseek(fp, offset, SEEK_SET);
2641: fread(buffer, sizeof(buffer), 1, fp);
2642: memset(path, 0, sizeof(path));
2643: fread(path, buffer[9], 1, fp);
2644: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
2645: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
2646: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
2647: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
2648: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
2649: } else {
2650: // read pe header of msdos.exe
2651: UINT8 header[0x400];
2652: fseek(fp, 0, SEEK_SET);
2653: fread(header, sizeof(header), 1, fp);
2654:
2655: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2656: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2657: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2658: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2659: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2660: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
2661: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2662:
2663: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
2664: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
2665: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
2666: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
2667: if(dwExtraLastSectionBytes != 0) {
2668: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
2669: dwLastSectionSize += dwRemain;
2670: }
2671: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
2672:
2673: // store msdos.exe
2674: fseek(fp, 0, SEEK_SET);
2675: for(int i = 0; i < dwEndOfFile; i++) {
2676: if((data = fgetc(fp)) != EOF) {
2677: fputc(data, fo);
2678: } else {
2679: // we should not reach here :-(
2680: fputc(0, fo);
2681: }
2682: }
2683:
2684: // store options
2685: UINT8 flags = 0;
2686: if(stay_busy) {
2687: flags |= 0x01;
2688: }
2689: if(no_windows) {
2690: flags |= 0x02;
2691: }
2692: if(standard_env) {
2693: flags |= 0x04;
2694: }
2695: if(ignore_illegal_insn) {
2696: flags |= 0x08;
2697: }
2698: if(limit_max_memory) {
2699: flags |= 0x10;
2700: }
1.1.1.29 root 2701: if(sio_port_number[0] != 0 || sio_port_number[1] != 0 || sio_port_number[2] != 0 || sio_port_number[3] != 0) {
1.1.1.28 root 2702: flags |= 0x20;
2703: }
2704: if(support_ems) {
2705: flags |= 0x40;
2706: }
1.1.1.30 root 2707: #ifdef SUPPORT_XMS
2708: if(support_xms) {
2709: flags |= 0x80;
2710: }
2711: #endif
1.1.1.28 root 2712:
2713: fputc(flags, fo);
2714: fputc((buf_width >> 0) & 0xff, fo);
2715: fputc((buf_width >> 8) & 0xff, fo);
2716: fputc((buf_height >> 0) & 0xff, fo);
2717: fputc((buf_height >> 8) & 0xff, fo);
1.1.1.30 root 2718: fputc(dos_major_version, fo);
2719: fputc(dos_minor_version, fo);
2720: fputc(win_major_version, fo);
2721: fputc(win_minor_version, fo);
1.1.1.28 root 2722: fputc((code_page >> 0) & 0xff, fo);
2723: fputc((code_page >> 8) & 0xff, fo);
2724:
2725: // store command file info
2726: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
2727: int name_len = strlen(name);
2728: fseek(fs, 0, SEEK_END);
2729: long file_size = ftell(fs);
2730:
2731: fputc(name_len, fo);
2732: fputc((file_size >> 0) & 0xff, fo);
2733: fputc((file_size >> 8) & 0xff, fo);
2734: fputc((file_size >> 16) & 0xff, fo);
2735: fputc((file_size >> 24) & 0xff, fo);
2736: fwrite(name, name_len, 1, fo);
2737:
2738: // store command file
2739: fseek(fs, 0, SEEK_SET);
2740: for(int i = 0; i < file_size; i++) {
2741: if((data = fgetc(fs)) != EOF) {
2742: fputc(data, fo);
2743: } else {
2744: // we should not reach here :-(
2745: fputc(0, fo);
2746: }
2747: }
2748:
2749: // store padding data and update pe header
1.1.1.29 root 2750: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
2751: coffHeader->NumberOfSections++;
2752: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
2753: memcpy(newSectionHeader->Name, ".msdos", 6);
2754: newSectionHeader->VirtualAddress = dwVirtualAddress;
2755: newSectionHeader->PointerToRawData = dwEndOfFile;
2756: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 2757: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
2758: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
2759: if(dwExtraRawBytes != 0) {
1.1.1.29 root 2760: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 2761: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
2762: for(int i = 0; i < dwRemain; i++) {
1.1.1.29 root 2763: if(i < 2) {
2764: fputc(padding[i & 15], fo);
2765: } else {
2766: fputc(padding[(i - 2) & 15], fo);
2767: }
1.1.1.28 root 2768: }
2769: newSectionHeader->SizeOfRawData += dwRemain;
2770: }
2771: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
2772:
2773: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
2774: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
2775: if(dwExtraNewSectionBytes != 0) {
2776: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
2777: dwNewSectionSize += dwRemain;
2778: }
2779: optionalHeader->SizeOfImage += dwNewSectionSize;
2780:
2781: fseek(fo, 0, SEEK_SET);
2782: fwrite(header, sizeof(header), 1, fo);
2783:
2784: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
2785: retval = EXIT_SUCCESS;
1.1.1.27 root 2786: }
2787: }
2788: if(fp != NULL) {
2789: fclose(fp);
2790: }
2791: if(fs != NULL) {
2792: fclose(fs);
2793: }
2794: if(fo != NULL) {
2795: fclose(fo);
2796: }
2797: }
2798: #ifdef _DEBUG
2799: _CrtDumpMemoryLeaks();
2800: #endif
2801: return(retval);
2802: }
1.1 root 2803:
1.1.1.14 root 2804: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
2805:
1.1.1.23 root 2806: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2807: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 2808: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 2809:
1.1.1.28 root 2810: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 2811: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 2812: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 2813:
1.1.1.14 root 2814: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
2815: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
2816: SCR_BUF(y,x).Char.AsciiChar = ' ';
2817: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 2818: }
2819: }
1.1.1.28 root 2820: if(get_console_info_success) {
1.1.1.12 root 2821: scr_width = csbi.dwSize.X;
1.1.1.14 root 2822: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2823:
1.1.1.28 root 2824: // v-text shadow buffer size must be lesser than 0x7fd0
2825: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 2826: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
2827: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
2828: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 2829: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 2830: scr_width = 80;
2831: scr_height = 25;
2832: }
1.1.1.28 root 2833: screen_size_changed = true;
1.1.1.14 root 2834: }
1.1.1.12 root 2835: } else {
2836: // for a proof (not a console)
2837: scr_width = 80;
2838: scr_height = 25;
2839: }
1.1.1.14 root 2840: scr_buf_size.X = scr_width;
2841: scr_buf_size.Y = scr_height;
2842: scr_buf_pos.X = scr_buf_pos.Y = 0;
2843: scr_top = csbi.srWindow.Top;
1.1 root 2844: cursor_moved = false;
2845:
1.1.1.35 root 2846: #ifdef USE_SERVICE_THREAD
2847: InitializeCriticalSection(&input_crit_sect);
2848: InitializeCriticalSection(&key_buf_crit_sect);
2849: InitializeCriticalSection(&putch_crit_sect);
1.1.1.50 root 2850: main_thread_id = GetCurrentThreadId();
1.1.1.35 root 2851: #endif
1.1.1.50 root 2852:
1.1.1.25 root 2853: key_buf_char = new FIFO(256);
2854: key_buf_scan = new FIFO(256);
1.1 root 2855:
2856: hardware_init();
2857:
1.1.1.33 root 2858: #ifdef USE_DEBUGGER
2859: debugger_init();
2860: #endif
2861:
1.1.1.9 root 2862: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 2863: retval = EXIT_FAILURE;
2864: } else {
1.1.1.27 root 2865: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 2866: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
2867: #endif
2868: SetConsoleCtrlHandler(ctrl_handler, TRUE);
2869:
1.1.1.28 root 2870: if(screen_size_changed) {
1.1.1.24 root 2871: change_console_size(scr_width, scr_height);
2872: }
1.1.1.8 root 2873: TIMECAPS caps;
2874: timeGetDevCaps(&caps, sizeof(TIMECAPS));
2875: timeBeginPeriod(caps.wPeriodMin);
1.1.1.35 root 2876: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2877: InitializeCriticalSection(&vram_crit_sect);
2878: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
2879: #endif
1.1.1.33 root 2880: #ifdef USE_DEBUGGER
2881: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL));
2882: // wait until telnet client starts and connects to me
2883: if(_access(debugger_get_ttermpro_path(), 0) == 0 ||
2884: _access(debugger_get_ttermpro_x86_path(), 0) == 0 ||
2885: _access(debugger_get_putty_path(), 0) == 0 ||
2886: _access(debugger_get_putty_x86_path(), 0) == 0 ||
2887: _access(debugger_get_telnet_path(), 0) == 0) {
2888: for(int i = 0; i < 100 && cli_socket == 0; i++) {
2889: Sleep(100);
2890: }
2891: }
2892: #endif
1.1 root 2893: hardware_run();
1.1.1.35 root 2894: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2895: vram_flush();
2896: DeleteCriticalSection(&vram_crit_sect);
2897: #endif
1.1.1.24 root 2898: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 2899:
1.1.1.24 root 2900: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 2901: if(get_console_info_success) {
1.1.1.23 root 2902: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2903: if(restore_console_on_exit) {
1.1.1.14 root 2904: // window can't be bigger than buffer,
2905: // buffer can't be smaller than window,
2906: // so make a tiny window,
2907: // set the required buffer,
2908: // then set the required window
2909: SMALL_RECT rect;
2910: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
2911: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 2912: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 2913: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 2914: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2915: }
1.1.1.14 root 2916: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
2917: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 2918: }
1.1.1.24 root 2919: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
2920:
1.1 root 2921: msdos_finish();
1.1.1.14 root 2922:
2923: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 2924: }
1.1.1.35 root 2925: if(temp_file_created) {
2926: DeleteFile(temp_file_path);
2927: temp_file_created = false;
2928: }
1.1.1.10 root 2929: hardware_finish();
2930:
1.1.1.28 root 2931: if(key_buf_char != NULL) {
2932: key_buf_char->release();
2933: delete key_buf_char;
2934: key_buf_char = NULL;
2935: }
2936: if(key_buf_scan != NULL) {
2937: key_buf_scan->release();
2938: delete key_buf_scan;
2939: key_buf_scan = NULL;
2940: }
1.1.1.35 root 2941: #ifdef USE_SERVICE_THREAD
2942: DeleteCriticalSection(&input_crit_sect);
2943: DeleteCriticalSection(&key_buf_crit_sect);
2944: DeleteCriticalSection(&putch_crit_sect);
2945: #endif
1.1.1.20 root 2946: #ifdef _DEBUG
2947: _CrtDumpMemoryLeaks();
2948: #endif
1.1 root 2949: return(retval);
2950: }
2951:
1.1.1.20 root 2952: /* ----------------------------------------------------------------------------
2953: console
2954: ---------------------------------------------------------------------------- */
2955:
1.1.1.14 root 2956: void change_console_size(int width, int height)
1.1.1.12 root 2957: {
1.1.1.23 root 2958: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2959: CONSOLE_SCREEN_BUFFER_INFO csbi;
2960: SMALL_RECT rect;
2961: COORD co;
2962:
2963: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 2964: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
2965: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
2966: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
2967: SET_RECT(rect, 0, 0, width - 1, height - 1);
2968: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2969: } else if(csbi.dwCursorPosition.Y > height - 1) {
2970: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
2971: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2972: SET_RECT(rect, 0, 0, width - 1, height - 1);
2973: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 2974: }
2975: }
1.1.1.14 root 2976: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 2977: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 2978: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 2979: SetConsoleCursorPosition(hStdout, co);
2980: cursor_moved = true;
2981: }
1.1.1.14 root 2982:
2983: // window can't be bigger than buffer,
2984: // buffer can't be smaller than window,
2985: // so make a tiny window,
2986: // set the required buffer,
2987: // then set the required window
2988: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 2989: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 2990: co.X = width;
2991: co.Y = height;
1.1.1.12 root 2992: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 2993: SET_RECT(rect, 0, 0, width - 1, height - 1);
2994: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2995:
2996: scr_width = scr_buf_size.X = width;
2997: scr_height = scr_buf_size.Y = height;
2998: scr_top = 0;
2999:
3000: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
3001:
3002: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 3003: text_vram_end_address = text_vram_top_address + regen;
3004: shadow_buffer_end_address = shadow_buffer_top_address + regen;
3005:
1.1.1.14 root 3006: if(regen > 0x4000) {
3007: regen = 0x8000;
3008: vram_pages = 1;
3009: } else if(regen > 0x2000) {
3010: regen = 0x4000;
3011: vram_pages = 2;
3012: } else if(regen > 0x1000) {
3013: regen = 0x2000;
3014: vram_pages = 4;
3015: } else {
3016: regen = 0x1000;
3017: vram_pages = 8;
3018: }
1.1.1.15 root 3019: *(UINT16 *)(mem + 0x44a) = scr_width;
3020: *(UINT16 *)(mem + 0x44c) = regen;
3021: *(UINT8 *)(mem + 0x484) = scr_height - 1;
3022:
1.1.1.24 root 3023: mouse.min_position.x = 0;
3024: mouse.min_position.y = 0;
1.1.1.34 root 3025: mouse.max_position.x = 8 * (scr_width - 1);
3026: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 3027:
1.1.1.15 root 3028: restore_console_on_exit = true;
1.1.1.14 root 3029: }
3030:
3031: void clear_scr_buffer(WORD attr)
3032: {
3033: for(int y = 0; y < scr_height; y++) {
3034: for(int x = 0; x < scr_width; x++) {
3035: SCR_BUF(y,x).Char.AsciiChar = ' ';
3036: SCR_BUF(y,x).Attributes = attr;
3037: }
3038: }
1.1.1.12 root 3039: }
3040:
1.1.1.24 root 3041: bool update_console_input()
1.1 root 3042: {
1.1.1.35 root 3043: #ifdef USE_SERVICE_THREAD
3044: EnterCriticalSection(&input_crit_sect);
3045: #endif
1.1.1.23 root 3046: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 3047: DWORD dwNumberOfEvents = 0;
1.1 root 3048: DWORD dwRead;
3049: INPUT_RECORD ir[16];
1.1.1.24 root 3050: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
3051: bool result = false;
1.1 root 3052:
1.1.1.8 root 3053: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
3054: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
3055: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 3056: if(ir[i].EventType & MOUSE_EVENT) {
1.1.1.34 root 3057: if(mouse.hidden == 0) {
3058: // NOTE: if restore_console_on_exit, console is not scrolled
3059: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
3060: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
3061: }
3062: // FIXME: character size is always 8x8 ???
3063: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
3064: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
3065:
3066: if(mouse.position.x != x || mouse.position.y != y) {
3067: mouse.position.x = x;
3068: mouse.position.y = y;
3069: mouse.status |= 1;
1.1.1.43 root 3070: mouse.status_alt |= 1;
1.1.1.34 root 3071: }
3072: }
3073: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
3074: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
3075: static const DWORD bits[] = {
3076: FROM_LEFT_1ST_BUTTON_PRESSED, // left
3077: RIGHTMOST_BUTTON_PRESSED, // right
3078: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
3079: };
3080: bool prev_status = mouse.buttons[i].status;
3081: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
3082:
3083: if(!prev_status && mouse.buttons[i].status) {
3084: mouse.buttons[i].pressed_times++;
3085: mouse.buttons[i].pressed_position.x = mouse.position.x;
3086: mouse.buttons[i].pressed_position.y = mouse.position.x;
1.1.1.43 root 3087: if(i < 2) {
3088: mouse.status_alt |= 2 << (i * 2);
3089: }
1.1.1.34 root 3090: mouse.status |= 2 << (i * 2);
3091: } else if(prev_status && !mouse.buttons[i].status) {
3092: mouse.buttons[i].released_times++;
3093: mouse.buttons[i].released_position.x = mouse.position.x;
3094: mouse.buttons[i].released_position.y = mouse.position.x;
1.1.1.43 root 3095: if(i < 2) {
3096: mouse.status_alt |= 4 << (i * 2);
3097: }
1.1.1.34 root 3098: mouse.status |= 4 << (i * 2);
1.1.1.14 root 3099: }
3100: }
3101: }
1.1.1.24 root 3102: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.33 root 3103: // update keyboard flags in bios data area
1.1.1.35 root 3104: if(ir[i].Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) {
3105: mem[0x417] |= 0x40;
1.1.1.33 root 3106: } else {
1.1.1.35 root 3107: mem[0x417] &= ~0x40;
1.1.1.33 root 3108: }
1.1.1.35 root 3109: if(ir[i].Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) {
3110: mem[0x417] |= 0x20;
1.1.1.33 root 3111: } else {
1.1.1.35 root 3112: mem[0x417] &= ~0x20;
3113: }
3114: if(ir[i].Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) {
3115: mem[0x417] |= 0x10;
3116: } else {
3117: mem[0x417] &= ~0x10;
1.1.1.33 root 3118: }
3119: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1.1.1.43 root 3120: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3121: mouse.status_alt |= 0x80;
3122: }
1.1.1.33 root 3123: mem[0x417] |= 0x08;
3124: } else {
3125: mem[0x417] &= ~0x08;
3126: }
1.1.1.35 root 3127: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1.1.1.43 root 3128: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3129: mouse.status_alt |= 0x40;
3130: }
1.1.1.35 root 3131: mem[0x417] |= 0x04;
1.1.1.33 root 3132: } else {
1.1.1.35 root 3133: mem[0x417] &= ~0x04;
1.1.1.33 root 3134: }
3135: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1.1.1.43 root 3136: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3137: mouse.status_alt |= 0x20;
3138: }
1.1.1.33 root 3139: if(!(mem[0x417] & 0x03)) {
3140: mem[0x417] |= 0x02; // left shift
3141: }
3142: } else {
3143: mem[0x417] &= ~0x03;
3144: }
1.1.1.35 root 3145: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) {
3146: mem[0x418] |= 0x02;
3147: } else {
3148: mem[0x418] &= ~0x02;
3149: }
3150: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
3151: mem[0x418] |= 0x01;
3152: } else {
3153: mem[0x418] &= ~0x01;
3154: }
1.1.1.33 root 3155:
1.1.1.28 root 3156: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 3157: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.33 root 3158: kbd_status |= 1;
3159:
3160: // update dos key buffer
3161: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
3162: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
1.1.1.51 root 3163: UINT8 scn_old = scn;
1.1.1.33 root 3164:
3165: if(ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 3166: // make
1.1.1.24 root 3167: kbd_data &= 0x7f;
3168:
1.1.1.33 root 3169: if(chr == 0x00) {
1.1.1.24 root 3170: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3171: if(scn >= 0x3b && scn <= 0x44) {
3172: scn += 0x68 - 0x3b; // F1 to F10
3173: } else if(scn == 0x57 || scn == 0x58) {
3174: scn += 0x8b - 0x57; // F11 & F12
3175: } else if(scn >= 0x47 && scn <= 0x53) {
3176: scn += 0x97 - 0x47; // edit/arrow clusters
3177: } else if(scn == 0x35) {
3178: scn = 0xa4; // keypad /
3179: }
3180: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3181: if(scn == 0x07) {
3182: chr = 0x1e; // Ctrl+^
3183: } else if(scn == 0x0c) {
3184: chr = 0x1f; // Ctrl+_
3185: } else if(scn >= 0x35 && scn <= 0x58) {
3186: static const UINT8 ctrl_map[] = {
3187: 0x95, // keypad /
3188: 0,
3189: 0x96, // keypad *
3190: 0, 0, 0,
3191: 0x5e, // F1
3192: 0x5f, // F2
3193: 0x60, // F3
3194: 0x61, // F4
3195: 0x62, // F5
3196: 0x63, // F6
3197: 0x64, // F7
3198: 0x65, // F8
3199: 0x66, // F9
3200: 0x67, // F10
3201: 0,
3202: 0,
3203: 0x77, // Home
3204: 0x8d, // Up
3205: 0x84, // PgUp
3206: 0x8e, // keypad -
3207: 0x73, // Left
3208: 0x8f, // keypad center
3209: 0x74, // Right
3210: 0x90, // keyapd +
3211: 0x75, // End
3212: 0x91, // Down
3213: 0x76, // PgDn
3214: 0x92, // Insert
3215: 0x93, // Delete
3216: 0, 0, 0,
3217: 0x89, // F11
3218: 0x8a, // F12
3219: };
3220: scn = ctrl_map[scn - 0x35];
3221: }
3222: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3223: if(scn >= 0x3b && scn <= 0x44) {
3224: scn += 0x54 - 0x3b; // F1 to F10
3225: } else if(scn == 0x57 || scn == 0x58) {
3226: scn += 0x87 - 0x57; // F11 & F12
3227: }
3228: } else if(scn == 0x57 || scn == 0x58) {
3229: scn += 0x85 - 0x57;
3230: }
3231: // ignore shift, ctrl, alt, win and menu keys
1.1.1.51 root 3232: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && !(scn >= 0x5b && scn <= 0x5d && scn == scn_old)) {
1.1.1.32 root 3233: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3234: #ifdef USE_SERVICE_THREAD
3235: EnterCriticalSection(&key_buf_crit_sect);
3236: #endif
1.1.1.32 root 3237: if(chr == 0) {
1.1.1.51 root 3238: pcbios_set_key_buffer(0x00, ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1.1.1.32 root 3239: }
1.1.1.51 root 3240: pcbios_set_key_buffer(chr, scn);
1.1.1.35 root 3241: #ifdef USE_SERVICE_THREAD
3242: LeaveCriticalSection(&key_buf_crit_sect);
3243: #endif
1.1.1.24 root 3244: }
3245: }
3246: } else {
3247: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3248: chr = 0;
3249: if(scn >= 0x02 && scn <= 0x0e) {
3250: scn += 0x78 - 0x02; // 1 to 0 - =
3251: }
3252: }
1.1.1.32 root 3253: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3254: #ifdef USE_SERVICE_THREAD
3255: EnterCriticalSection(&key_buf_crit_sect);
3256: #endif
1.1.1.51 root 3257: pcbios_set_key_buffer(chr, scn);
1.1.1.35 root 3258: #ifdef USE_SERVICE_THREAD
3259: LeaveCriticalSection(&key_buf_crit_sect);
3260: #endif
1.1.1.32 root 3261: }
1.1.1.24 root 3262: }
1.1.1.33 root 3263: } else if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) {
3264: // ctrl-break, ctrl-c
3265: if(scn == 0x46) {
3266: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3267: #ifdef USE_SERVICE_THREAD
3268: EnterCriticalSection(&key_buf_crit_sect);
3269: #endif
1.1.1.51 root 3270: pcbios_set_key_buffer(0x00, 0x00);
1.1.1.35 root 3271: #ifdef USE_SERVICE_THREAD
3272: LeaveCriticalSection(&key_buf_crit_sect);
3273: #endif
1.1.1.33 root 3274: }
3275: ctrl_break_pressed = true;
3276: mem[0x471] = 0x80;
3277: raise_int_1bh = true;
3278: } else {
3279: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3280: #ifdef USE_SERVICE_THREAD
3281: EnterCriticalSection(&key_buf_crit_sect);
3282: #endif
1.1.1.51 root 3283: pcbios_set_key_buffer(chr, scn);
1.1.1.35 root 3284: #ifdef USE_SERVICE_THREAD
3285: LeaveCriticalSection(&key_buf_crit_sect);
3286: #endif
1.1.1.33 root 3287: }
3288: ctrl_c_pressed = (scn == 0x2e);
3289: }
3290: } else {
3291: // break
3292: kbd_data |= 0x80;
1.1 root 3293: }
1.1.1.24 root 3294: result = key_changed = true;
1.1.1.36 root 3295: // IME may be on and it may causes screen scroll up and cursor position change
3296: cursor_moved = true;
1.1 root 3297: }
3298: }
3299: }
3300: }
1.1.1.35 root 3301: #ifdef USE_SERVICE_THREAD
3302: LeaveCriticalSection(&input_crit_sect);
3303: #endif
1.1.1.24 root 3304: return(result);
1.1.1.8 root 3305: }
3306:
1.1.1.14 root 3307: bool update_key_buffer()
1.1.1.8 root 3308: {
1.1.1.35 root 3309: if(update_console_input()) {
3310: return(true);
3311: }
3312: if(key_buf_char != NULL && key_buf_scan != NULL) {
3313: #ifdef USE_SERVICE_THREAD
3314: EnterCriticalSection(&key_buf_crit_sect);
3315: #endif
3316: bool empty = key_buf_char->empty();
3317: #ifdef USE_SERVICE_THREAD
3318: LeaveCriticalSection(&key_buf_crit_sect);
3319: #endif
3320: if(!empty) return(true);
3321: }
3322: return(false);
1.1.1.8 root 3323: }
3324:
1.1.1.20 root 3325: /* ----------------------------------------------------------------------------
3326: MS-DOS virtual machine
3327: ---------------------------------------------------------------------------- */
3328:
1.1.1.32 root 3329: static const struct {
1.1.1.33 root 3330: char *name;
3331: DWORD lcid;
3332: char *std;
3333: char *dlt;
3334: } tz_table[] = {
3335: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
3336: // 0 GMT Greenwich Mean Time GMT0
3337: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
3338: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
3339: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
3340: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
3341: // 2 FST FDT Fernando De Noronha Std FST2FDT
3342: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3343: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3344: // 3 BST Brazil Standard Time BST3
3345: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
3346: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
3347: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
3348: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
3349: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
3350: // 3 GST Greenland Standard Time GST3
3351: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
3352: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
3353: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
3354: // 4 AST ADT Atlantic Standard Time AST4ADT
3355: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
3356: // 4 WST WDT Western Standard (Brazil) WST4WDT
3357: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
3358: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
3359: // 5 EST EDT Eastern Standard Time EST5EDT
3360: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
3361: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
3362: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
3363: // 5 CST CDT Chile Standard Time CST5CDT
3364: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
3365: // 5 AST ADT Acre Standard Time AST5ADT
3366: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
3367: // 5 CST CDT Cuba Standard Time CST5CDT
3368: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
3369: // 6 CST CDT Central Standard Time CST6CDT
3370: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
3371: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
3372: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
3373: // 6 EST EDT Easter Island Standard EST6EDT
3374: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
3375: // 7 MST MDT Mountain Standard Time MST7MDT
3376: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
3377: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
3378: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
3379: // 8 PST PDT Pacific Standard Time PST8PDT
3380: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
3381: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
3382: // 9 AKS AKD Alaska Standard Time AKS9AKD
3383: // 9 YST YDT Yukon Standard Time YST9YST
3384: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
3385: // 10 HST HDT Hawaii Standard Time HST10HDT
3386: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
3387: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
3388: // 11 SST Samoa Standard Time SST11
3389: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
3390: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
3391: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
3392: // -10 GST Guam Standard Time GST-10
3393: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
3394: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
3395: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
3396: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
3397: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
3398: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
3399: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
3400: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
3401: // -9 JST Japan Standard Time JST-9
3402: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
3403: // -9 KST KDT Korean Standard Time KST-9KDT
3404: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
3405: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
3406: // -8 HKT Hong Kong Time HKT-8
3407: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
3408: // -8 CCT China Coast Time CCT-8
3409: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
3410: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
3411: // -8 SST Singapore Standard Time SST-8
3412: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
3413: // -8 WAS WAD Western Australian Standard WAS-8WAD
3414: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
3415: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
3416: // -7:30 JT Java Standard Time JST-7:30
3417: // -7 NST North Sumatra Time NST-7
3418: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
3419: // -5:30 IST Indian Standard Time IST-5:30
3420: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
3421: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
3422: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
3423: // -3 MSK MSD Moscow Winter Time MSK-3MSD
3424: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
3425: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
3426: // -2 EET Eastern Europe Time EET-2
3427: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
3428: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
3429: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
3430: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
3431: // -2 IST IDT Israel Standard Time IST-2IDT
3432: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
3433: // -1 MEZ MES Middle European Time MEZ-1MES
3434: // -1 SWT SST Swedish Winter Time SWT-1SST
3435: // -1 FWT FST French Winter Time FWT-1FST
3436: // -1 CET CES Central European Time CET-1CES
3437: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
3438: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
3439: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
3440: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
3441: // -1 WAT West African Time WAT-1
3442: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
3443: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
3444: // 0 UTC Universal Coordinated Time UTC0
3445: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
3446: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
3447: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
3448: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
3449: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
3450: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
3451: };
3452:
1.1.1.53! root 3453: // FIXME: consider to build on non-Japanese environment :-(
! 3454: // message_japanese string must be in shift-jis
! 3455:
1.1.1.33 root 3456: static const struct {
1.1.1.32 root 3457: UINT16 code;
3458: char *message_english;
3459: char *message_japanese;
3460: } standard_error_table[] = {
3461: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3462: {0x02, "File not found", "�t�@�C����������܂���."},
3463: {0x03, "Path not found", "�p�X��������܂���."},
3464: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3465: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3466: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3467: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3468: {0x08, "Insufficient memory", "������������܂���."},
3469: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3470: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3471: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3472: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3473: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3474: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3475: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3476: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3477: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3478: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3479: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3480: {0x15, "Not ready", "�������ł��Ă��܂���."},
3481: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3482: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3483: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3484: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3485: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3486: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3487: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3488: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3489: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3490: {0x1F, "General failure", "�G���[�ł�."},
3491: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3492: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3493: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3494: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3495: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3496: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3497: {0x26, "Out of input", "���͂��I���܂���."},
3498: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3499: /*
3500: {0x32, "Network request not supported", NULL},
3501: {0x33, "Remote computer not listening", NULL},
3502: {0x34, "Duplicate name on network", NULL},
3503: {0x35, "Network name not found", NULL},
3504: {0x36, "Network busy", NULL},
3505: {0x37, "Network device no longer exists", NULL},
3506: {0x38, "Network BIOS command limit exceeded", NULL},
3507: {0x39, "Network adapter hardware error", NULL},
3508: {0x3A, "Incorrect response from network", NULL},
3509: {0x3B, "Unexpected network error", NULL},
3510: {0x3C, "Incompatible remote adapter", NULL},
3511: {0x3D, "Print queue full", NULL},
3512: {0x3E, "Queue not full", NULL},
3513: {0x3F, "Not enough space to print file", NULL},
3514: {0x40, "Network name was deleted", NULL},
3515: {0x41, "Network: Access denied", NULL},
3516: {0x42, "Network device type incorrect", NULL},
3517: {0x43, "Network name not found", NULL},
3518: {0x44, "Network name limit exceeded", NULL},
3519: {0x45, "Network BIOS session limit exceeded", NULL},
3520: {0x46, "Temporarily paused", NULL},
3521: {0x47, "Network request not accepted", NULL},
3522: {0x48, "Network print/disk redirection paused", NULL},
3523: {0x49, "Network software not installed", NULL},
3524: {0x4A, "Unexpected adapter close", NULL},
3525: */
3526: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
1.1.1.33 root 3527: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
1.1.1.32 root 3528: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3529: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3530: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3531: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3532: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3533: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3534: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3535: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
1.1.1.53! root 3536: #ifdef SUPPORT_MSCDEX
1.1.1.32 root 3537: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3538: {0x65, "Not ready", "�������ł��Ă��܂���."},
3539: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3540: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3541: {0x68, "Door open", "���o�[���܂��Ă��܂���."
1.1.1.53! root 3542: #endif
1.1.1.32 root 3543: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3544: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3545: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3546: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3547: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3548: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3549: };
3550:
3551: static const struct {
3552: UINT16 code;
3553: char *message_english;
3554: char *message_japanese;
3555: } param_error_table[] = {
3556: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3557: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3558: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3559: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3560: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3561: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3562: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3563: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3564: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3565: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3566: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3567: };
3568:
3569: static const struct {
3570: UINT16 code;
3571: char *message_english;
3572: char *message_japanese;
3573: } critical_error_table[] = {
3574: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3575: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3576: {0x02, "Not ready", "�������ł��Ă��܂���."},
3577: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3578: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3579: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3580: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3581: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3582: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3583: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3584: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3585: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3586: {0x0C, "General failure", "�G���[�ł�."},
3587: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3588: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3589: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3590: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3591: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3592: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3593: {0x13, "Out of input", "���͂��I���܂���."},
3594: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3595: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3596: };
3597:
1.1.1.20 root 3598: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3599: int msdos_psp_get_file_table(int fd, int psp_seg);
3600: void msdos_putch(UINT8 data);
1.1.1.50 root 3601: void msdos_putch_fast(UINT8 data);
1.1.1.35 root 3602: #ifdef USE_SERVICE_THREAD
3603: void msdos_putch_tmp(UINT8 data);
3604: #endif
1.1.1.45 root 3605: const char *msdos_short_path(const char *path);
1.1.1.44 root 3606: bool msdos_is_valid_drive(int drv);
3607: bool msdos_is_removable_drive(int drv);
3608: bool msdos_is_cdrom_drive(int drv);
3609: bool msdos_is_remote_drive(int drv);
3610: bool msdos_is_subst_drive(int drv);
1.1.1.20 root 3611:
1.1 root 3612: // process info
3613:
3614: process_t *msdos_process_info_create(UINT16 psp_seg)
3615: {
3616: for(int i = 0; i < MAX_PROCESS; i++) {
3617: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3618: memset(&process[i], 0, sizeof(process_t));
3619: process[i].psp = psp_seg;
3620: return(&process[i]);
3621: }
3622: }
3623: fatalerror("too many processes\n");
3624: return(NULL);
3625: }
3626:
1.1.1.52 root 3627: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error = true)
1.1 root 3628: {
3629: for(int i = 0; i < MAX_PROCESS; i++) {
3630: if(process[i].psp == psp_seg) {
3631: return(&process[i]);
3632: }
3633: }
1.1.1.33 root 3634: if(show_error) {
3635: fatalerror("invalid psp address\n");
3636: }
1.1 root 3637: return(NULL);
3638: }
3639:
1.1.1.23 root 3640: void msdos_sda_update(int psp_seg)
3641: {
3642: sda_t *sda = (sda_t *)(mem + SDA_TOP);
3643:
3644: for(int i = 0; i < MAX_PROCESS; i++) {
3645: if(process[i].psp == psp_seg) {
3646: sda->switchar = process[i].switchar;
3647: sda->current_dta.w.l = process[i].dta.w.l;
3648: sda->current_dta.w.h = process[i].dta.w.h;
3649: sda->current_psp = process[i].psp;
3650: break;
3651: }
3652: }
3653: sda->malloc_strategy = malloc_strategy;
3654: sda->return_code = retval;
3655: sda->current_drive = _getdrive();
3656: }
3657:
1.1.1.13 root 3658: // dta info
3659:
3660: void msdos_dta_info_init()
3661: {
1.1.1.14 root 3662: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 3663: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3664: }
3665: }
3666:
3667: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
3668: {
3669: dtainfo_t *free_dta = NULL;
1.1.1.14 root 3670: for(int i = 0; i < MAX_DTAINFO; i++) {
3671: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
3672: if(free_dta == NULL) {
1.1.1.13 root 3673: free_dta = &dtalist[i];
3674: }
1.1.1.14 root 3675: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 3676: return(&dtalist[i]);
3677: }
3678: }
1.1.1.14 root 3679: if(free_dta) {
1.1.1.13 root 3680: free_dta->psp = psp_seg;
3681: free_dta->dta = dta_laddr;
3682: return(free_dta);
3683: }
3684: fatalerror("too many dta\n");
3685: return(NULL);
3686: }
3687:
3688: void msdos_dta_info_free(UINT16 psp_seg)
3689: {
1.1.1.14 root 3690: for(int i = 0; i < MAX_DTAINFO; i++) {
3691: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 3692: FindClose(dtalist[i].find_handle);
3693: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3694: }
3695: }
3696: }
3697:
1.1 root 3698: void msdos_cds_update(int drv)
3699: {
1.1.1.44 root 3700: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv);
1.1 root 3701:
1.1.1.44 root 3702: memset(cds, 0, 88);
3703:
3704: if(msdos_is_valid_drive(drv)) {
3705: char path[MAX_PATH];
3706: if(msdos_is_remote_drive(drv)) {
3707: cds->drive_attrib = 0xc000; // network drive
3708: } else if(msdos_is_subst_drive(drv)) {
3709: cds->drive_attrib = 0x5000; // subst drive
3710: } else {
3711: cds->drive_attrib = 0x4000; // physical drive
3712: }
3713: if(_getdcwd(drv + 1, path, MAX_PATH) != NULL) {
3714: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path));
3715: }
3716: }
3717: if(cds->path_name[0] == '\0') {
3718: sprintf(cds->path_name, "%c:\\", 'A' + drv);
3719: }
3720: cds->dpb_ptr.w.h = DPB_TOP >> 4;
3721: cds->dpb_ptr.w.l = sizeof(dpb_t) * drv;
3722: cds->word_1 = cds->word_2 = 0xffff;
3723: cds->word_3 = 0xffff; // stored user data from INT 21/AX=5F03h if this is network drive
3724: cds->bs_offset = 2;
3725: }
3726:
1.1.1.45 root 3727: void msdos_cds_update(int drv, const char *path)
1.1.1.44 root 3728: {
3729: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv);
3730:
3731: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path));
1.1 root 3732: }
3733:
1.1.1.17 root 3734: // nls information tables
3735:
3736: // uppercase table (func 6502h)
3737: void msdos_upper_table_update()
3738: {
3739: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3740: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3741: UINT8 c[4];
1.1.1.33 root 3742: *(UINT32 *)c = 0; // reset internal conversion state
3743: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.17 root 3744: c[0] = 0x80 + i;
3745: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
3746: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3747: }
3748: }
3749:
1.1.1.23 root 3750: // lowercase table (func 6503h)
3751: void msdos_lower_table_update()
3752: {
3753: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
3754: for(unsigned i = 0; i < 0x80; ++i) {
3755: UINT8 c[4];
1.1.1.33 root 3756: *(UINT32 *)c = 0; // reset internal conversion state
3757: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.23 root 3758: c[0] = 0x80 + i;
3759: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
3760: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3761: }
3762: }
3763:
1.1.1.17 root 3764: // filename uppercase table (func 6504h)
3765: void msdos_filename_upper_table_init()
3766: {
3767: // depended on (file)system, not on active codepage
3768: // temporary solution: just filling data
3769: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3770: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3771: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
3772: }
3773: }
3774:
3775: // filaname terminator table (func 6505h)
3776: void msdos_filename_terminator_table_init()
3777: {
3778: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
3779: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
3780:
3781: data[2] = 1; // marker? (permissible character value)
3782: data[3] = 0x00; // 00h...FFh
3783: data[4] = 0xff;
3784: data[5] = 0; // marker? (excluded character)
3785: data[6] = 0x00; // 00h...20h
3786: data[7] = 0x20;
3787: data[8] = 2; // marker? (illegal characters for filename)
3788: data[9] = (UINT8)strlen(illegal_chars);
3789: memcpy(data + 10, illegal_chars, data[9]);
3790:
3791: // total length
3792: *(UINT16 *)data = (10 - 2) + data[9];
3793: }
3794:
3795: // collating table (func 6506h)
3796: void msdos_collating_table_update()
3797: {
3798: // temporary solution: just filling data
3799: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 3800: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 3801: mem[COLLATING_TABLE_TOP + 2 + i] = i;
3802: }
3803: }
3804:
1.1 root 3805: // dbcs
3806:
3807: void msdos_dbcs_table_update()
3808: {
3809: UINT8 dbcs_data[DBCS_SIZE];
3810: memset(dbcs_data, 0, sizeof(dbcs_data));
3811:
3812: CPINFO info;
3813: GetCPInfo(active_code_page, &info);
3814:
3815: if(info.MaxCharSize != 1) {
3816: for(int i = 0;; i += 2) {
3817: UINT8 lo = info.LeadByte[i + 0];
3818: UINT8 hi = info.LeadByte[i + 1];
3819: dbcs_data[2 + i + 0] = lo;
3820: dbcs_data[2 + i + 1] = hi;
3821: if(lo == 0 && hi == 0) {
3822: dbcs_data[0] = i + 2;
3823: break;
3824: }
3825: }
3826: } else {
3827: dbcs_data[0] = 2; // ???
3828: }
3829: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
3830: }
3831:
1.1.1.17 root 3832: void msdos_dbcs_table_finish()
3833: {
1.1.1.32 root 3834: if(system_code_page != _getmbcp()) {
1.1.1.17 root 3835: _setmbcp(system_code_page);
3836: }
1.1.1.32 root 3837: if(console_code_page != GetConsoleCP()) {
3838: SetConsoleCP(console_code_page);
3839: SetConsoleOutputCP(console_code_page);
3840: }
1.1.1.17 root 3841: }
3842:
3843: void msdos_nls_tables_init()
1.1 root 3844: {
1.1.1.32 root 3845: active_code_page = console_code_page = GetConsoleCP();
3846: system_code_page = _getmbcp();
3847:
3848: if(active_code_page != system_code_page) {
3849: if(_setmbcp(active_code_page) != 0) {
3850: active_code_page = system_code_page;
3851: }
3852: }
3853:
1.1.1.17 root 3854: msdos_upper_table_update();
1.1.1.23 root 3855: msdos_lower_table_update();
1.1.1.17 root 3856: msdos_filename_terminator_table_init();
3857: msdos_filename_upper_table_init();
3858: msdos_collating_table_update();
1.1 root 3859: msdos_dbcs_table_update();
3860: }
3861:
1.1.1.17 root 3862: void msdos_nls_tables_update()
1.1 root 3863: {
1.1.1.17 root 3864: msdos_dbcs_table_update();
3865: msdos_upper_table_update();
1.1.1.23 root 3866: msdos_lower_table_update();
3867: // msdos_collating_table_update();
1.1 root 3868: }
3869:
3870: int msdos_lead_byte_check(UINT8 code)
3871: {
3872: UINT8 *dbcs_table = mem + DBCS_TABLE;
3873:
3874: for(int i = 0;; i += 2) {
3875: UINT8 lo = dbcs_table[i + 0];
3876: UINT8 hi = dbcs_table[i + 1];
3877: if(lo == 0 && hi == 0) {
3878: break;
3879: }
3880: if(lo <= code && code <= hi) {
3881: return(1);
3882: }
3883: }
3884: return(0);
3885: }
3886:
1.1.1.20 root 3887: int msdos_ctrl_code_check(UINT8 code)
3888: {
1.1.1.22 root 3889: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 3890: }
3891:
1.1.1.36 root 3892: int msdos_kanji_2nd_byte_check(UINT8 *buf, int n)
3893: {
3894: int is_kanji_1st = 0;
3895: int is_kanji_2nd = 0;
3896:
3897: for(int p = 0;; p++) {
3898: if(is_kanji_1st) {
3899: is_kanji_1st = 0;
3900: is_kanji_2nd = 1;
3901: } else if(msdos_lead_byte_check(buf[p])) {
3902: is_kanji_1st = 1;
3903: }
3904: if(p == n) {
3905: return(is_kanji_2nd);
3906: }
3907: is_kanji_2nd = 0;
3908: }
3909: }
3910:
1.1 root 3911: // file control
3912:
1.1.1.45 root 3913: const char *msdos_remove_double_quote(const char *path)
1.1.1.14 root 3914: {
3915: static char tmp[MAX_PATH];
3916:
3917: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1.1.1.45 root 3918: memset(tmp, 0, sizeof(tmp));
1.1.1.14 root 3919: memcpy(tmp, path + 1, strlen(path) - 2);
3920: } else {
3921: strcpy(tmp, path);
3922: }
3923: return(tmp);
3924: }
3925:
1.1.1.45 root 3926: const char *msdos_remove_end_separator(const char *path)
1.1.1.32 root 3927: {
3928: static char tmp[MAX_PATH];
3929:
3930: strcpy(tmp, path);
1.1.1.45 root 3931:
3932: // for example "C:\" case, the end separator should not be removed
3933: if(strlen(tmp) > 3 && tmp[strlen(tmp) - 1] == '\\') {
3934: tmp[strlen(tmp) - 1] = '\0';
1.1.1.32 root 3935: }
3936: return(tmp);
3937: }
3938:
1.1.1.45 root 3939: const char *msdos_combine_path(const char *dir, const char *file)
1.1.1.14 root 3940: {
3941: static char tmp[MAX_PATH];
1.1.1.45 root 3942: const char *tmp_dir = msdos_remove_double_quote(dir);
1.1.1.14 root 3943:
3944: if(strlen(tmp_dir) == 0) {
3945: strcpy(tmp, file);
3946: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
3947: sprintf(tmp, "%s%s", tmp_dir, file);
3948: } else {
3949: sprintf(tmp, "%s\\%s", tmp_dir, file);
3950: }
3951: return(tmp);
3952: }
3953:
1.1.1.45 root 3954: const char *msdos_trimmed_path(const char *path, int lfn)
1.1 root 3955: {
3956: static char tmp[MAX_PATH];
3957:
3958: if(lfn) {
3959: strcpy(tmp, path);
3960: } else {
3961: // remove space in the path
1.1.1.45 root 3962: const char *src = path;
3963: char *dst = tmp;
1.1 root 3964:
3965: while(*src != '\0') {
3966: if(msdos_lead_byte_check(*src)) {
3967: *dst++ = *src++;
3968: *dst++ = *src++;
3969: } else if(*src != ' ') {
3970: *dst++ = *src++;
3971: } else {
3972: src++; // skip space
3973: }
3974: }
3975: *dst = '\0';
3976: }
1.1.1.14 root 3977: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
3978: // redirect C:\COMMAND.COM to comspec_path
3979: strcpy(tmp, comspec_path);
3980: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
3981: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
3982: static int root_drive_protected = -1;
3983: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
3984: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
3985:
3986: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
3987: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
3988: strcpy(name, name_temp);
3989: name_temp[0] = '\0';
3990:
3991: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
3992: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
3993: if(root_drive_protected == -1) {
3994: FILE *fp = NULL;
3995:
3996: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
3997: root_drive_protected = 1;
3998: try {
3999: if((fp = fopen(temp, "w")) != NULL) {
4000: if(fprintf(fp, "TEST") == 4) {
4001: root_drive_protected = 0;
4002: }
4003: }
4004: } catch(...) {
4005: }
4006: if(fp != NULL) {
4007: fclose(fp);
4008: }
4009: if(_access(temp, 0) == 0) {
4010: remove(temp);
4011: }
4012: }
4013: if(root_drive_protected == 1) {
4014: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
4015: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
4016: strcpy(tmp, msdos_combine_path(temp, name));
4017: }
4018: }
4019: }
4020: }
4021: }
1.1 root 4022: return(tmp);
4023: }
4024:
1.1.1.45 root 4025: const char *msdos_get_multiple_short_path(const char *src)
1.1.1.28 root 4026: {
1.1.1.32 root 4027: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 4028: static char env_path[ENV_SIZE];
4029: char tmp[ENV_SIZE], *token;
4030:
4031: memset(env_path, 0, sizeof(env_path));
4032: strcpy(tmp, src);
4033: token = my_strtok(tmp, ";");
4034:
4035: while(token != NULL) {
4036: if(token[0] != '\0') {
1.1.1.45 root 4037: const char *path = msdos_remove_double_quote(token);
4038: char short_path[MAX_PATH];
1.1.1.32 root 4039: if(path != NULL && strlen(path) != 0) {
4040: if(env_path[0] != '\0') {
4041: strcat(env_path, ";");
4042: }
1.1.1.28 root 4043: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32 root 4044: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 4045: } else {
4046: my_strupr(short_path);
1.1.1.32 root 4047: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 4048: }
4049: }
4050: }
4051: token = my_strtok(NULL, ";");
4052: }
4053: return(env_path);
4054: }
4055:
1.1.1.45 root 4056: bool match(const char *text, const char *pattern)
1.1 root 4057: {
1.1.1.24 root 4058: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 4059: switch(*pattern) {
1.1 root 4060: case '\0':
4061: return !*text;
4062: case '*':
1.1.1.14 root 4063: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 4064: case '?':
4065: return *text && match(text + 1, pattern + 1);
4066: default:
4067: return (*text == *pattern) && match(text + 1, pattern + 1);
4068: }
4069: }
4070:
1.1.1.45 root 4071: bool msdos_match_volume_label(const char *path, const char *volume)
1.1 root 4072: {
1.1.1.45 root 4073: const char *p = NULL;
1.1 root 4074:
1.1.1.14 root 4075: if(!*volume) {
4076: return false;
4077: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 4078: return msdos_match_volume_label(p + 1, volume);
4079: } else if((p = my_strchr(path, '\\')) != NULL) {
4080: return msdos_match_volume_label(p + 1, volume);
4081: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 4082: char tmp[MAX_PATH];
4083: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
4084: return match(volume, tmp);
1.1 root 4085: } else {
4086: return match(volume, path);
4087: }
4088: }
4089:
1.1.1.45 root 4090: const char *msdos_fcb_path(fcb_t *fcb)
1.1 root 4091: {
4092: static char tmp[MAX_PATH];
4093: char name[9], ext[4];
4094:
4095: memset(name, 0, sizeof(name));
4096: memcpy(name, fcb->file_name, 8);
4097: strcpy(name, msdos_trimmed_path(name, 0));
4098:
4099: memset(ext, 0, sizeof(ext));
4100: memcpy(ext, fcb->file_name + 8, 3);
4101: strcpy(ext, msdos_trimmed_path(ext, 0));
4102:
4103: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
4104: strcpy(name, "*");
4105: }
4106: if(ext[0] == '\0') {
4107: strcpy(tmp, name);
4108: } else {
4109: if(strcmp(ext, "???") == 0) {
4110: strcpy(ext, "*");
4111: }
4112: sprintf(tmp, "%s.%s", name, ext);
4113: }
4114: return(tmp);
4115: }
4116:
1.1.1.45 root 4117: void msdos_set_fcb_path(fcb_t *fcb, const char *path)
1.1 root 4118: {
4119: char *ext = my_strchr(path, '.');
4120:
4121: memset(fcb->file_name, 0x20, 8 + 3);
4122: if(ext != NULL && path[0] != '.') {
4123: *ext = '\0';
4124: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
4125: }
4126: memcpy(fcb->file_name, path, strlen(path));
4127: }
4128:
1.1.1.45 root 4129: const char *msdos_short_path(const char *path)
1.1 root 4130: {
4131: static char tmp[MAX_PATH];
4132:
1.1.1.24 root 4133: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
4134: strcpy(tmp, path);
4135: }
1.1 root 4136: my_strupr(tmp);
4137: return(tmp);
4138: }
4139:
1.1.1.45 root 4140: const char *msdos_short_name(WIN32_FIND_DATA *fd)
1.1.1.13 root 4141: {
4142: static char tmp[MAX_PATH];
1.1.1.45 root 4143:
1.1.1.14 root 4144: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4145: strcpy(tmp, fd->cAlternateFileName);
4146: } else {
4147: strcpy(tmp, fd->cFileName);
4148: }
4149: my_strupr(tmp);
4150: return(tmp);
4151: }
4152:
1.1.1.45 root 4153: const char *msdos_short_full_path(const char *path)
1.1 root 4154: {
4155: static char tmp[MAX_PATH];
4156: char full[MAX_PATH], *name;
4157:
1.1.1.14 root 4158: // Full works with non-existent files, but Short does not
1.1 root 4159: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 4160: *tmp = '\0';
4161: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
4162: name[-1] = '\0';
4163: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
4164: if(len == 0) {
4165: strcpy(tmp, full);
4166: } else {
4167: tmp[len++] = '\\';
4168: strcpy(tmp + len, name);
4169: }
4170: }
1.1 root 4171: my_strupr(tmp);
4172: return(tmp);
4173: }
4174:
1.1.1.45 root 4175: const char *msdos_short_full_dir(const char *path)
1.1 root 4176: {
4177: static char tmp[MAX_PATH];
4178: char full[MAX_PATH], *name;
4179:
4180: GetFullPathName(path, MAX_PATH, full, &name);
4181: name[-1] = '\0';
1.1.1.24 root 4182: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
4183: strcpy(tmp, full);
4184: }
1.1 root 4185: my_strupr(tmp);
4186: return(tmp);
4187: }
4188:
1.1.1.45 root 4189: const char *msdos_local_file_path(const char *path, int lfn)
1.1 root 4190: {
1.1.1.45 root 4191: static char trimmed[MAX_PATH];
4192:
4193: strcpy(trimmed, msdos_trimmed_path(path, lfn));
1.1.1.14 root 4194: #if 0
4195: // I have forgotten the reason of this routine... :-(
1.1 root 4196: if(_access(trimmed, 0) != 0) {
4197: process_t *process = msdos_process_info_get(current_psp);
4198: static char tmp[MAX_PATH];
4199:
4200: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
4201: if(_access(tmp, 0) == 0) {
4202: return(tmp);
4203: }
4204: }
1.1.1.14 root 4205: #endif
1.1 root 4206: return(trimmed);
4207: }
4208:
1.1.1.45 root 4209: bool msdos_is_device_path(const char *path)
1.1.1.11 root 4210: {
4211: char full[MAX_PATH], *name;
4212:
1.1.1.24 root 4213: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4214: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4215: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4216: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4217: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4218: _stricmp(full, "\\\\.\\COM1") == 0 ||
4219: _stricmp(full, "\\\\.\\COM2") == 0 ||
4220: _stricmp(full, "\\\\.\\COM3") == 0 ||
4221: _stricmp(full, "\\\\.\\COM4") == 0 ||
4222: _stricmp(full, "\\\\.\\COM5") == 0 ||
4223: _stricmp(full, "\\\\.\\COM6") == 0 ||
4224: _stricmp(full, "\\\\.\\COM7") == 0 ||
4225: _stricmp(full, "\\\\.\\COM8") == 0 ||
4226: _stricmp(full, "\\\\.\\COM9") == 0 ||
4227: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4228: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4229: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4230: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4231: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4232: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4233: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4234: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4235: _stricmp(full, "\\\\.\\LPT9") == 0) {
4236: return(true);
4237: } else if(name != NULL) {
4238: if(_stricmp(name, "CLOCK$" ) == 0 ||
4239: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 4240: _stricmp(name, "EMMXXXX0") == 0 ||
1.1.1.43 root 4241: // _stricmp(name, "SCSIMGR$") == 0 ||
1.1.1.30 root 4242: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 4243: return(true);
4244: }
4245: }
1.1.1.24 root 4246: }
4247: return(false);
1.1.1.11 root 4248: }
4249:
1.1.1.45 root 4250: bool msdos_is_con_path(const char *path)
1.1.1.8 root 4251: {
1.1.1.14 root 4252: char full[MAX_PATH], *name;
1.1.1.8 root 4253:
1.1.1.24 root 4254: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4255: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 4256: }
4257: return(false);
4258: }
4259:
1.1.1.45 root 4260: int msdos_is_comm_path(const char *path)
1.1.1.24 root 4261: {
4262: char full[MAX_PATH], *name;
4263:
4264: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4265: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4266: return(1);
4267: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4268: return(2);
4269: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4270: return(3);
4271: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4272: return(4);
1.1.1.24 root 4273: }
4274: }
1.1.1.29 root 4275: return(0);
4276: }
4277:
1.1.1.45 root 4278: void msdos_set_comm_params(int sio_port, const char *path)
1.1.1.37 root 4279: {
4280: // COM1:{110,150,300,600,1200,2400,4800,9600},{N,O,E,M,S},{8,7,6,5},{1,1.5,2}
1.1.1.45 root 4281: const char *p = NULL;
1.1.1.37 root 4282:
4283: if((p = strstr(path, ":")) != NULL) {
4284: UINT8 selector = sio_read(sio_port - 1, 3);
4285:
4286: // baud rate
4287: int baud = max(110, min(9600, atoi(p + 1)));
4288: UINT16 divisor = 115200 / baud;
4289:
4290: if((p = strstr(p + 1, ",")) != NULL) {
4291: // parity
4292: if(p[1] == 'N' || p[1] == 'n') {
4293: selector = (selector & ~0x38) | 0x00;
4294: } else if(p[1] == 'O' || p[1] == 'o') {
4295: selector = (selector & ~0x38) | 0x08;
4296: } else if(p[1] == 'E' || p[1] == 'e') {
4297: selector = (selector & ~0x38) | 0x18;
4298: } else if(p[1] == 'M' || p[1] == 'm') {
4299: selector = (selector & ~0x38) | 0x28;
4300: } else if(p[1] == 'S' || p[1] == 's') {
4301: selector = (selector & ~0x38) | 0x38;
4302: }
4303: if((p = strstr(p + 1, ",")) != NULL) {
4304: // word length
4305: if(p[1] == '8') {
4306: selector = (selector & ~0x03) | 0x03;
4307: } else if(p[1] == '7') {
4308: selector = (selector & ~0x03) | 0x02;
4309: } else if(p[1] == '6') {
4310: selector = (selector & ~0x03) | 0x01;
4311: } else if(p[1] == '5') {
4312: selector = (selector & ~0x03) | 0x00;
4313: }
4314: if((p = strstr(p + 1, ",")) != NULL) {
4315: // stop bits
4316: float bits = atof(p + 1);
4317: if(bits > 1.0F) {
4318: selector |= 0x04;
4319: } else {
4320: selector &= ~0x04;
4321: }
4322: }
4323: }
4324: }
4325: sio_write(sio_port - 1, 3, selector | 0x80);
4326: sio_write(sio_port - 1, 0, divisor & 0xff);
4327: sio_write(sio_port - 1, 1, divisor >> 8);
4328: sio_write(sio_port - 1, 3, selector);
4329: }
4330: }
4331:
1.1.1.45 root 4332: int msdos_is_prn_path(const char *path)
1.1.1.30 root 4333: {
4334: char full[MAX_PATH], *name;
4335:
4336: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4337: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4338: return(1);
4339: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4340: return(1);
4341: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4342: return(2);
4343: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4344: return(3);
4345: }
4346: }
4347: return(0);
4348: }
4349:
1.1.1.44 root 4350: bool msdos_is_valid_drive(int drv)
4351: {
4352: return(drv >= 0 && drv < 26 && (GetLogicalDrives() & (1 << drv)) != 0);
4353: }
4354:
4355: bool msdos_is_removable_drive(int drv)
4356: {
4357: char volume[] = "A:\\";
4358:
4359: volume[0] = 'A' + drv;
4360:
4361: return(GetDriveType(volume) == DRIVE_REMOVABLE);
4362: }
4363:
4364: bool msdos_is_cdrom_drive(int drv)
4365: {
4366: char volume[] = "A:\\";
4367:
4368: volume[0] = 'A' + drv;
4369:
4370: return(GetDriveType(volume) == DRIVE_CDROM);
4371: }
4372:
4373: bool msdos_is_remote_drive(int drv)
4374: {
4375: char volume[] = "A:\\";
4376:
4377: volume[0] = 'A' + drv;
4378:
4379: return(GetDriveType(volume) == DRIVE_REMOTE);
4380: }
4381:
4382: bool msdos_is_subst_drive(int drv)
4383: {
4384: char device[] = "A:", path[MAX_PATH];
4385:
4386: device[0] = 'A' + drv;
4387:
4388: if(QueryDosDevice(device, path, MAX_PATH)) {
4389: if(strncmp(path, "\\??\\", 4) == 0) {
4390: return(true);
4391: }
4392: }
4393: return(false);
4394: }
4395:
1.1.1.45 root 4396: bool msdos_is_existing_file(const char *path)
1.1.1.24 root 4397: {
4398: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4399: WIN32_FIND_DATA FindData;
4400: HANDLE hFind;
4401:
4402: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
4403: FindClose(hFind);
4404: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
4405: }
4406: return(false);
1.1.1.8 root 4407: }
4408:
1.1.1.45 root 4409: const char *msdos_search_command_com(const char *command_path, const char *env_path)
1.1.1.9 root 4410: {
4411: static char tmp[MAX_PATH];
1.1.1.28 root 4412: char path[ENV_SIZE], *file_name;
1.1.1.9 root 4413:
1.1.1.28 root 4414: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 4415: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
4416: sprintf(file_name, "COMMAND.COM");
4417: if(_access(tmp, 0) == 0) {
4418: return(tmp);
4419: }
4420: }
1.1.1.28 root 4421:
4422: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 4423: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
4424: sprintf(file_name, "COMMAND.COM");
4425: if(_access(tmp, 0) == 0) {
4426: return(tmp);
4427: }
4428: }
1.1.1.28 root 4429:
4430: // check if COMMAND.COM is in the current directory
1.1.1.9 root 4431: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4432: if(_access(tmp, 0) == 0) {
4433: return(tmp);
4434: }
4435: }
1.1.1.28 root 4436:
4437: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4438: strcpy(path, env_path);
4439: char *token = my_strtok(path, ";");
1.1.1.9 root 4440: while(token != NULL) {
1.1.1.14 root 4441: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 4442: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4443: if(_access(tmp, 0) == 0) {
4444: return(tmp);
4445: }
4446: }
4447: token = my_strtok(NULL, ";");
4448: }
4449: return(NULL);
4450: }
4451:
1.1.1.14 root 4452: int msdos_drive_number(const char *path)
1.1 root 4453: {
4454: char tmp[MAX_PATH], *name;
4455:
1.1.1.45 root 4456: if(GetFullPathName(path, MAX_PATH, tmp, &name) >= 2 && tmp[1] == ':') {
4457: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4458: return(tmp[0] - 'a');
4459: } else if(tmp[0] >= 'A' && tmp[0] <= 'Z') {
4460: return(tmp[0] - 'A');
4461: }
1.1 root 4462: }
1.1.1.45 root 4463: // return(msdos_drive_number("."));
4464: return(_getdrive() - 1);
1.1 root 4465: }
4466:
1.1.1.45 root 4467: const char *msdos_volume_label(const char *path)
1.1 root 4468: {
4469: static char tmp[MAX_PATH];
4470: char volume[] = "A:\\";
4471:
4472: if(path[1] == ':') {
4473: volume[0] = path[0];
4474: } else {
4475: volume[0] = 'A' + _getdrive() - 1;
4476: }
4477: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4478: memset(tmp, 0, sizeof(tmp));
4479: }
4480: return(tmp);
4481: }
4482:
1.1.1.45 root 4483: const char *msdos_short_volume_label(const char *label)
1.1 root 4484: {
4485: static char tmp[(8 + 1 + 3) + 1];
1.1.1.45 root 4486: const char *src = label;
1.1 root 4487: int remain = strlen(label);
4488: char *dst_n = tmp;
4489: char *dst_e = tmp + 9;
4490:
4491: strcpy(tmp, " . ");
4492: for(int i = 0; i < 8 && remain > 0; i++) {
4493: if(msdos_lead_byte_check(*src)) {
4494: if(++i == 8) {
4495: break;
4496: }
4497: *dst_n++ = *src++;
4498: remain--;
4499: }
4500: *dst_n++ = *src++;
4501: remain--;
4502: }
4503: if(remain > 0) {
4504: for(int i = 0; i < 3 && remain > 0; i++) {
4505: if(msdos_lead_byte_check(*src)) {
4506: if(++i == 3) {
4507: break;
4508: }
4509: *dst_e++ = *src++;
4510: remain--;
4511: }
4512: *dst_e++ = *src++;
4513: remain--;
4514: }
4515: *dst_e = '\0';
4516: } else {
4517: *dst_n = '\0';
4518: }
4519: my_strupr(tmp);
4520: return(tmp);
4521: }
4522:
1.1.1.13 root 4523: errno_t msdos_maperr(unsigned long oserrno)
4524: {
4525: _doserrno = oserrno;
1.1.1.14 root 4526: switch(oserrno) {
1.1.1.13 root 4527: case ERROR_FILE_NOT_FOUND: // 2
4528: case ERROR_PATH_NOT_FOUND: // 3
4529: case ERROR_INVALID_DRIVE: // 15
4530: case ERROR_NO_MORE_FILES: // 18
4531: case ERROR_BAD_NETPATH: // 53
4532: case ERROR_BAD_NET_NAME: // 67
4533: case ERROR_BAD_PATHNAME: // 161
4534: case ERROR_FILENAME_EXCED_RANGE: // 206
4535: return ENOENT;
4536: case ERROR_TOO_MANY_OPEN_FILES: // 4
4537: return EMFILE;
4538: case ERROR_ACCESS_DENIED: // 5
4539: case ERROR_CURRENT_DIRECTORY: // 16
4540: case ERROR_NETWORK_ACCESS_DENIED: // 65
4541: case ERROR_CANNOT_MAKE: // 82
4542: case ERROR_FAIL_I24: // 83
4543: case ERROR_DRIVE_LOCKED: // 108
4544: case ERROR_SEEK_ON_DEVICE: // 132
4545: case ERROR_NOT_LOCKED: // 158
4546: case ERROR_LOCK_FAILED: // 167
4547: return EACCES;
4548: case ERROR_INVALID_HANDLE: // 6
4549: case ERROR_INVALID_TARGET_HANDLE: // 114
4550: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4551: return EBADF;
4552: case ERROR_ARENA_TRASHED: // 7
4553: case ERROR_NOT_ENOUGH_MEMORY: // 8
4554: case ERROR_INVALID_BLOCK: // 9
4555: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4556: return ENOMEM;
4557: case ERROR_BAD_ENVIRONMENT: // 10
4558: return E2BIG;
4559: case ERROR_BAD_FORMAT: // 11
4560: return ENOEXEC;
4561: case ERROR_NOT_SAME_DEVICE: // 17
4562: return EXDEV;
4563: case ERROR_FILE_EXISTS: // 80
4564: case ERROR_ALREADY_EXISTS: // 183
4565: return EEXIST;
4566: case ERROR_NO_PROC_SLOTS: // 89
4567: case ERROR_MAX_THRDS_REACHED: // 164
4568: case ERROR_NESTING_NOT_ALLOWED: // 215
4569: return EAGAIN;
4570: case ERROR_BROKEN_PIPE: // 109
4571: return EPIPE;
4572: case ERROR_DISK_FULL: // 112
4573: return ENOSPC;
4574: case ERROR_WAIT_NO_CHILDREN: // 128
4575: case ERROR_CHILD_NOT_COMPLETE: // 129
4576: return ECHILD;
4577: case ERROR_DIR_NOT_EMPTY: // 145
4578: return ENOTEMPTY;
4579: }
1.1.1.14 root 4580: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 4581: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4582: return EACCES;
4583: }
1.1.1.14 root 4584: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 4585: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4586: return ENOEXEC;
4587: }
4588: return EINVAL;
4589: }
4590:
1.1.1.45 root 4591: int msdos_open(const char *path, int oflag)
1.1.1.13 root 4592: {
1.1.1.14 root 4593: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.45 root 4594: return(_open(path, oflag));
1.1.1.13 root 4595: }
1.1.1.14 root 4596:
4597: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 4598: DWORD disposition;
1.1.1.14 root 4599: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4600: default:
1.1.1.13 root 4601: case _O_EXCL:
4602: disposition = OPEN_EXISTING;
4603: break;
4604: case _O_CREAT:
4605: disposition = OPEN_ALWAYS;
4606: break;
4607: case _O_CREAT | _O_EXCL:
4608: case _O_CREAT | _O_TRUNC | _O_EXCL:
4609: disposition = CREATE_NEW;
4610: break;
4611: case _O_TRUNC:
4612: case _O_TRUNC | _O_EXCL:
4613: disposition = TRUNCATE_EXISTING;
4614: break;
4615: case _O_CREAT | _O_TRUNC:
4616: disposition = CREATE_ALWAYS;
4617: break;
4618: }
1.1.1.14 root 4619:
1.1.1.45 root 4620: HANDLE h = CreateFile(path, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1.1.1.13 root 4621: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4622: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4623: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4624: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4625: // Retry without FILE_WRITE_ATTRIBUTES.
1.1.1.45 root 4626: h = CreateFile(path, GENERIC_READ,
1.1.1.13 root 4627: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4628: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4629: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4630: errno = msdos_maperr(GetLastError());
1.1.1.45 root 4631: return(-1);
1.1.1.13 root 4632: }
4633: }
1.1.1.14 root 4634:
1.1.1.13 root 4635: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 4636: if(fd == -1) {
1.1.1.13 root 4637: CloseHandle(h);
4638: }
1.1.1.45 root 4639: return(fd);
4640: }
4641:
4642: int msdos_open_device(const char *path, int oflag, int *sio_port, int *lpt_port)
4643: {
4644: int fd = -1;
4645:
4646: *sio_port = *lpt_port = 0;
4647:
4648: if(msdos_is_con_path(path)) {
4649: // MODE.COM opens CON device with read/write mode :-(
4650: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) == _O_RDWR) {
4651: oflag &= ~(_O_RDONLY | _O_WRONLY | _O_RDWR);
4652: oflag |= _O_RDONLY;
4653: }
4654: if((fd = msdos_open("CON", oflag)) == -1) {
4655: // fd = msdos_open("NUL", oflag);
4656: }
4657: } else if((*sio_port = msdos_is_comm_path(path)) != 0) {
4658: fd = msdos_open("NUL", oflag);
4659: msdos_set_comm_params(*sio_port, path);
4660: } else if((*lpt_port = msdos_is_prn_path(path)) != 0) {
4661: fd = msdos_open("NUL", oflag);
4662: } else if(msdos_is_device_path(path)) {
4663: fd = msdos_open("NUL", oflag);
4664: // } else if(oflag & _O_CREAT) {
4665: // fd = _open(path, oflag, _S_IREAD | _S_IWRITE);
4666: // } else {
4667: // fd = _open(path, oflag);
4668: }
4669: return(fd);
4670: }
4671:
4672: UINT16 msdos_device_info(const char *path)
4673: {
4674: if(msdos_is_con_path(path)) {
4675: return(0x80d3);
4676: } else if(msdos_is_comm_path(path)) {
4677: return(0x80a0);
4678: } else if(msdos_is_prn_path(path)) {
4679: // return(0xa8c0);
4680: return(0x80a0);
4681: } else if(msdos_is_device_path(path)) {
4682: if(strstr(path, "EMMXXXX0") != NULL) {
4683: return(0xc0c0);
4684: } else if(strstr(path, "MSCD001") != NULL) {
4685: return(0xc880);
4686: } else {
4687: return(0x8084);
4688: }
4689: } else {
4690: return(msdos_drive_number(path));
4691: }
1.1.1.13 root 4692: }
4693:
1.1.1.52 root 4694: 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)
1.1 root 4695: {
4696: static int id = 0;
4697: char full[MAX_PATH], *name;
4698:
4699: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4700: strcpy(file_handler[fd].path, full);
4701: } else {
4702: strcpy(file_handler[fd].path, path);
4703: }
1.1.1.14 root 4704: // isatty makes no distinction between CON & NUL
4705: // GetFileSize fails on CON, succeeds on NUL
4706: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
1.1.1.45 root 4707: if(info == 0x80d3) {
4708: info = 0x8084;
4709: }
1.1.1.14 root 4710: atty = 0;
4711: } else if(!atty && info == 0x80d3) {
1.1.1.45 root 4712: // info = msdos_drive_number(".");
4713: info = msdos_drive_number(path);
1.1.1.14 root 4714: }
1.1 root 4715: file_handler[fd].valid = 1;
4716: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1.1.1.37 root 4717: file_handler[fd].atty = (sio_port == 0 && lpt_port == 0) ? atty : 0;
1.1 root 4718: file_handler[fd].mode = mode;
4719: file_handler[fd].info = info;
4720: file_handler[fd].psp = psp_seg;
1.1.1.37 root 4721: file_handler[fd].sio_port = sio_port;
4722: file_handler[fd].lpt_port = lpt_port;
1.1.1.21 root 4723:
4724: // init system file table
4725: if(fd < 20) {
4726: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
4727:
4728: memset(sft, 0, 0x3b);
4729:
4730: *(UINT16 *)(sft + 0x00) = 1;
4731: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
4732: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
4733: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
4734:
4735: if(!(file_handler[fd].info & 0x80)) {
4736: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
4737: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
4738:
4739: FILETIME time, local;
4740: HANDLE hHandle;
4741: WORD dos_date = 0, dos_time = 0;
4742: DWORD file_size = 0;
4743: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
4744: if(GetFileTime(hHandle, NULL, NULL, &time)) {
4745: FileTimeToLocalFileTime(&time, &local);
4746: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
4747: }
4748: file_size = GetFileSize(hHandle, NULL);
4749: }
4750: *(UINT16 *)(sft + 0x0d) = dos_time;
4751: *(UINT16 *)(sft + 0x0f) = dos_date;
4752: *(UINT32 *)(sft + 0x11) = file_size;
4753: }
4754:
4755: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
4756: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
4757: my_strupr(fname);
4758: my_strupr(ext);
4759: memset(sft + 0x20, 0x20, 11);
4760: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
4761: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
4762:
4763: *(UINT16 *)(sft + 0x31) = psp_seg;
4764: }
1.1 root 4765: }
4766:
4767: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
4768: {
4769: strcpy(file_handler[dst].path, file_handler[src].path);
4770: file_handler[dst].valid = 1;
4771: file_handler[dst].id = file_handler[src].id;
4772: file_handler[dst].atty = file_handler[src].atty;
4773: file_handler[dst].mode = file_handler[src].mode;
4774: file_handler[dst].info = file_handler[src].info;
4775: file_handler[dst].psp = psp_seg;
1.1.1.37 root 4776: file_handler[dst].sio_port = file_handler[src].sio_port;
4777: file_handler[dst].lpt_port = file_handler[src].lpt_port;
1.1 root 4778: }
4779:
1.1.1.20 root 4780: void msdos_file_handler_close(int fd)
1.1 root 4781: {
4782: file_handler[fd].valid = 0;
1.1.1.21 root 4783:
4784: if(fd < 20) {
4785: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
4786: }
1.1 root 4787: }
4788:
1.1.1.14 root 4789: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 4790: {
1.1.1.14 root 4791: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
4792: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
4793: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 4794: }
4795:
4796: // find file
4797:
4798: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
4799: {
4800: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4801: return(0); // search directory only !!!
4802: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
4803: return(0);
4804: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
4805: return(0);
4806: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4807: return(0);
4808: } else if((attribute & required_mask) != required_mask) {
4809: return(0);
4810: } else {
4811: return(1);
4812: }
4813: }
4814:
1.1.1.13 root 4815: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
4816: {
1.1.1.14 root 4817: if(fd->cAlternateFileName[0]) {
1.1.1.42 root 4818: return(1);
1.1.1.13 root 4819: }
4820: size_t len = strlen(fd->cFileName);
1.1.1.14 root 4821: if(len > 12) {
1.1.1.42 root 4822: return(0);
1.1.1.13 root 4823: }
4824: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 4825: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.42 root 4826: return(0);
1.1.1.13 root 4827: }
1.1.1.42 root 4828: return(1);
1.1.1.13 root 4829: }
4830:
1.1 root 4831: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
4832: {
4833: FILETIME local;
4834:
4835: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
4836: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
4837: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
4838:
4839: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
4840: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
4841: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
4842:
4843: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
4844: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
4845: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
4846: }
4847:
4848: // i/o
4849:
4850: void msdos_stdio_reopen()
4851: {
4852: if(!file_handler[0].valid) {
4853: _dup2(DUP_STDIN, 0);
4854: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
4855: }
4856: if(!file_handler[1].valid) {
4857: _dup2(DUP_STDOUT, 1);
4858: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
4859: }
4860: if(!file_handler[2].valid) {
4861: _dup2(DUP_STDERR, 2);
4862: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
4863: }
1.1.1.21 root 4864: if(!file_handler[3].valid) {
4865: _dup2(DUP_STDAUX, 3);
4866: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
4867: }
4868: if(!file_handler[4].valid) {
4869: _dup2(DUP_STDPRN, 4);
1.1.1.45 root 4870: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
4871: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1
1.1.1.21 root 4872: }
4873: for(int i = 0; i < 5; i++) {
4874: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
4875: msdos_psp_set_file_table(i, i, current_psp);
4876: }
4877: }
1.1 root 4878: }
4879:
1.1.1.37 root 4880: int msdos_read(int fd, void *buffer, unsigned int count)
4881: {
4882: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
4883: // read from serial port
4884: int read = 0;
4885: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
4886: UINT8 *buf = (UINT8 *)buffer;
4887: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
4888: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
1.1.1.38 root 4889: DWORD timeout = timeGetTime() + 1000;
4890: while(read < count) {
4891: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x01) {
4892: buf[read++] = sio_read(file_handler[fd].sio_port - 1, 0);
4893: timeout = timeGetTime() + 1000;
4894: } else {
4895: if(timeGetTime() > timeout) {
4896: break;
4897: }
4898: Sleep(10);
1.1.1.37 root 4899: }
4900: }
4901: sio_write(file_handler[fd].sio_port - 1, 3, selector);
4902: }
4903: return(read);
4904: }
4905: return(_read(fd, buffer, count));
4906: }
4907:
1.1 root 4908: int msdos_kbhit()
4909: {
4910: msdos_stdio_reopen();
4911:
1.1.1.20 root 4912: process_t *process = msdos_process_info_get(current_psp);
4913: int fd = msdos_psp_get_file_table(0, current_psp);
4914:
4915: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4916: // stdin is redirected to file
1.1.1.20 root 4917: return(eof(fd) == 0);
1.1 root 4918: }
4919:
4920: // check keyboard status
1.1.1.35 root 4921: if(key_recv != 0) {
1.1 root 4922: return(1);
4923: }
1.1.1.35 root 4924: if(key_buf_char != NULL && key_buf_scan != NULL) {
4925: #ifdef USE_SERVICE_THREAD
4926: EnterCriticalSection(&key_buf_crit_sect);
4927: #endif
4928: bool empty = key_buf_char->empty();
4929: #ifdef USE_SERVICE_THREAD
4930: LeaveCriticalSection(&key_buf_crit_sect);
4931: #endif
4932: if(!empty) return(1);
4933: }
4934: return(_kbhit());
1.1 root 4935: }
4936:
4937: int msdos_getch_ex(int echo)
4938: {
4939: static char prev = 0;
4940:
4941: msdos_stdio_reopen();
4942:
1.1.1.20 root 4943: process_t *process = msdos_process_info_get(current_psp);
4944: int fd = msdos_psp_get_file_table(0, current_psp);
4945:
4946: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4947: // stdin is redirected to file
4948: retry:
4949: char data;
1.1.1.37 root 4950: if(msdos_read(fd, &data, 1) == 1) {
1.1 root 4951: char tmp = data;
4952: if(data == 0x0a) {
4953: if(prev == 0x0d) {
4954: goto retry; // CRLF -> skip LF
4955: } else {
4956: data = 0x0d; // LF only -> CR
4957: }
4958: }
4959: prev = tmp;
4960: return(data);
4961: }
4962: return(EOF);
4963: }
4964:
4965: // input from console
1.1.1.5 root 4966: int key_char, key_scan;
1.1.1.33 root 4967: if(key_recv != 0) {
1.1.1.5 root 4968: key_char = (key_code >> 0) & 0xff;
4969: key_scan = (key_code >> 8) & 0xff;
4970: key_code >>= 16;
1.1.1.33 root 4971: key_recv >>= 16;
1.1.1.5 root 4972: } else {
1.1.1.35 root 4973: while(key_buf_char != NULL && key_buf_scan != NULL && !m_halted) {
4974: if(key_buf_char != NULL && key_buf_scan != NULL) {
4975: #ifdef USE_SERVICE_THREAD
4976: EnterCriticalSection(&key_buf_crit_sect);
4977: #endif
4978: bool empty = key_buf_char->empty();
4979: #ifdef USE_SERVICE_THREAD
4980: LeaveCriticalSection(&key_buf_crit_sect);
4981: #endif
4982: if(!empty) break;
4983: }
1.1.1.23 root 4984: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
4985: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
4986: if(_kbhit()) {
1.1.1.32 root 4987: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4988: #ifdef USE_SERVICE_THREAD
4989: EnterCriticalSection(&key_buf_crit_sect);
4990: #endif
1.1.1.51 root 4991: pcbios_set_key_buffer(_getch(), 0x00);
1.1.1.35 root 4992: #ifdef USE_SERVICE_THREAD
4993: LeaveCriticalSection(&key_buf_crit_sect);
4994: #endif
1.1.1.32 root 4995: }
1.1.1.23 root 4996: } else {
4997: Sleep(10);
4998: }
4999: } else {
5000: if(!update_key_buffer()) {
5001: Sleep(10);
5002: }
1.1.1.14 root 5003: }
5004: }
5005: if(m_halted) {
1.1.1.33 root 5006: // insert CR to terminate input loops
1.1.1.14 root 5007: key_char = 0x0d;
5008: key_scan = 0;
1.1.1.32 root 5009: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 5010: #ifdef USE_SERVICE_THREAD
5011: EnterCriticalSection(&key_buf_crit_sect);
5012: #endif
1.1.1.51 root 5013: pcbios_get_key_buffer(&key_char, &key_scan);
1.1.1.35 root 5014: #ifdef USE_SERVICE_THREAD
5015: LeaveCriticalSection(&key_buf_crit_sect);
5016: #endif
1.1.1.5 root 5017: }
1.1 root 5018: }
5019: if(echo && key_char) {
5020: msdos_putch(key_char);
5021: }
5022: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
5023: }
5024:
5025: inline int msdos_getch()
5026: {
5027: return(msdos_getch_ex(0));
5028: }
5029:
5030: inline int msdos_getche()
5031: {
5032: return(msdos_getch_ex(1));
5033: }
5034:
5035: int msdos_write(int fd, const void *buffer, unsigned int count)
5036: {
1.1.1.37 root 5037: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
5038: // write to serial port
1.1.1.38 root 5039: int written = 0;
1.1.1.37 root 5040: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
5041: UINT8 *buf = (UINT8 *)buffer;
5042: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
5043: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
1.1.1.38 root 5044: DWORD timeout = timeGetTime() + 1000;
5045: while(written < count) {
5046: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x20) {
5047: sio_write(file_handler[fd].sio_port - 1, 0, buf[written++]);
5048: timeout = timeGetTime() + 1000;
5049: } else {
5050: if(timeGetTime() > timeout) {
5051: break;
5052: }
5053: Sleep(10);
5054: }
1.1.1.37 root 5055: }
5056: sio_write(file_handler[fd].sio_port - 1, 3, selector);
5057: }
1.1.1.38 root 5058: return(written);
1.1.1.37 root 5059: } else if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].lpt_port >= 1 && file_handler[fd].lpt_port <= 3) {
5060: // write to printer port
5061: UINT8 *buf = (UINT8 *)buffer;
5062: for(unsigned int i = 0; i < count; i++) {
5063: // printer_out(file_handler[fd].lpt_port - 1, buf[i]);
5064: pcbios_printer_out(file_handler[fd].lpt_port - 1, buf[i]);
5065: }
5066: return(count);
5067: } else if(fd == 1 && file_handler[1].valid && !file_handler[1].atty) {
1.1 root 5068: // CR+LF -> LF
1.1.1.37 root 5069: static int is_cr = 0;
1.1 root 5070: UINT8 *buf = (UINT8 *)buffer;
5071: for(unsigned int i = 0; i < count; i++) {
5072: UINT8 data = buf[i];
5073: if(is_cr) {
5074: if(data != 0x0a) {
5075: UINT8 tmp = 0x0d;
5076: _write(1, &tmp, 1);
5077: }
5078: _write(1, &data, 1);
5079: is_cr = 0;
5080: } else if(data == 0x0d) {
5081: is_cr = 1;
5082: } else {
5083: _write(1, &data, 1);
5084: }
5085: }
5086: return(count);
5087: }
1.1.1.14 root 5088: vram_flush();
1.1 root 5089: return(_write(fd, buffer, count));
5090: }
5091:
5092: void msdos_putch(UINT8 data)
1.1.1.50 root 5093: {
5094: msdos_stdio_reopen();
5095:
5096: process_t *process = msdos_process_info_get(current_psp);
5097: int fd = msdos_psp_get_file_table(1, current_psp);
5098:
5099: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
5100: // stdout is redirected to file
5101: msdos_write(fd, &data, 1);
5102: return;
5103: }
5104:
5105: // call int 29h ?
5106: if(*(UINT16 *)(mem + 4 * 0x29 + 0) == 0x29 &&
5107: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
5108: // int 29h is not hooked, no need to call int 29h
5109: msdos_putch_fast(data);
5110: #ifdef USE_SERVICE_THREAD
5111: } else if(in_service && main_thread_id != GetCurrentThreadId()) {
5112: // XXX: in usually we should not reach here
5113: // this is called from service thread to echo the input
5114: // we can not call int 29h because it causes a critial issue to control cpu running in main thread :-(
5115: msdos_putch_fast(data);
5116: #endif
1.1.1.51 root 5117: } else if(in_service_29h) {
1.1.1.50 root 5118: // disallow reentering call int 29h routine to prevent an infinite loop :-(
5119: msdos_putch_fast(data);
5120: } else {
5121: // this is called from main thread, so we can call int 29h :-)
1.1.1.51 root 5122: in_service_29h = true;
1.1.1.50 root 5123: try {
5124: UINT32 tmp_pc = m_pc;
5125: UINT16 tmp_ax = REG16(AX);
5126: UINT32 tmp_bx = REG16(BX); // BX may be destroyed by some versions of DOS 3.3
5127:
5128: // call int 29h routine is at fffc:0027
5129: i386_call_far(DUMMY_TOP >> 4, 0x0027);
5130: REG8(AL) = data;
5131:
5132: // run cpu until call int 29h routine is done
5133: while(!m_halted && tmp_pc != m_pc) {
5134: try {
5135: hardware_run_cpu();
5136: } catch(...) {
5137: }
5138: }
5139: REG16(AX) = tmp_ax;
5140: REG16(BX) = tmp_bx;
5141: } catch(...) {
5142: }
1.1.1.51 root 5143: in_service_29h = false;
1.1.1.50 root 5144: }
5145: }
5146:
5147: void msdos_putch_fast(UINT8 data)
1.1.1.35 root 5148: #ifdef USE_SERVICE_THREAD
5149: {
5150: EnterCriticalSection(&putch_crit_sect);
5151: msdos_putch_tmp(data);
5152: LeaveCriticalSection(&putch_crit_sect);
5153: }
5154: void msdos_putch_tmp(UINT8 data)
5155: #endif
1.1 root 5156: {
1.1.1.34 root 5157: CONSOLE_SCREEN_BUFFER_INFO csbi;
5158: SMALL_RECT rect;
5159: COORD co;
1.1 root 5160: static int p = 0;
5161: static int is_kanji = 0;
5162: static int is_esc = 0;
5163: static int stored_x;
5164: static int stored_y;
5165: static WORD stored_a;
1.1.1.20 root 5166: static char tmp[64], out[64];
1.1 root 5167:
1.1.1.23 root 5168: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 5169:
5170: // output to console
5171: tmp[p++] = data;
5172:
1.1.1.14 root 5173: vram_flush();
5174:
1.1 root 5175: if(is_kanji) {
5176: // kanji character
5177: is_kanji = 0;
5178: } else if(is_esc) {
5179: // escape sequense
5180: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
5181: p = is_esc = 0;
5182: } else if(tmp[1] == '=' && p == 4) {
5183: co.X = tmp[3] - 0x20;
1.1.1.14 root 5184: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 5185: SetConsoleCursorPosition(hStdout, co);
5186: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5187: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 5188: cursor_moved = false;
5189: p = is_esc = 0;
5190: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
5191: GetConsoleScreenBufferInfo(hStdout, &csbi);
5192: co.X = csbi.dwCursorPosition.X;
5193: co.Y = csbi.dwCursorPosition.Y;
5194: WORD wAttributes = csbi.wAttributes;
5195:
5196: if(tmp[1] == 'D') {
5197: co.Y++;
5198: } else if(tmp[1] == 'E') {
5199: co.X = 0;
5200: co.Y++;
5201: } else if(tmp[1] == 'M') {
5202: co.Y--;
5203: } else if(tmp[1] == '*') {
1.1.1.14 root 5204: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5205: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5206: co.X = 0;
5207: co.Y = csbi.srWindow.Top;
1.1 root 5208: } else if(tmp[1] == '[') {
5209: int param[256], params = 0;
5210: memset(param, 0, sizeof(param));
5211: for(int i = 2; i < p; i++) {
5212: if(tmp[i] >= '0' && tmp[i] <= '9') {
5213: param[params] *= 10;
5214: param[params] += tmp[i] - '0';
5215: } else {
5216: params++;
5217: }
5218: }
5219: if(data == 'A') {
1.1.1.14 root 5220: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 5221: } else if(data == 'B') {
1.1.1.14 root 5222: co.Y += (params == 0) ? 1 : param[0];
1.1 root 5223: } else if(data == 'C') {
1.1.1.14 root 5224: co.X += (params == 0) ? 1 : param[0];
1.1 root 5225: } else if(data == 'D') {
1.1.1.14 root 5226: co.X -= (params == 0) ? 1 : param[0];
1.1 root 5227: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 5228: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
5229: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 5230: } else if(data == 'J') {
1.1.1.14 root 5231: clear_scr_buffer(csbi.wAttributes);
1.1 root 5232: if(param[0] == 0) {
5233: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5234: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5235: if(co.Y < csbi.srWindow.Bottom) {
5236: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5237: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5238: }
5239: } else if(param[0] == 1) {
1.1.1.14 root 5240: if(co.Y > csbi.srWindow.Top) {
5241: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
5242: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5243: }
5244: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5245: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5246: } else if(param[0] == 2) {
1.1.1.14 root 5247: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5248: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5249: co.X = co.Y = 0;
5250: }
5251: } else if(data == 'K') {
1.1.1.14 root 5252: clear_scr_buffer(csbi.wAttributes);
1.1 root 5253: if(param[0] == 0) {
5254: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5255: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5256: } else if(param[0] == 1) {
5257: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5258: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5259: } else if(param[0] == 2) {
5260: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5261: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5262: }
5263: } else if(data == 'L') {
1.1.1.14 root 5264: if(params == 0) {
5265: param[0] = 1;
1.1 root 5266: }
1.1.1.14 root 5267: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5268: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5269: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5270: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5271: clear_scr_buffer(csbi.wAttributes);
1.1 root 5272: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 5273: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5274: co.X = 0;
5275: } else if(data == 'M') {
1.1.1.14 root 5276: if(params == 0) {
5277: param[0] = 1;
5278: }
5279: if(co.Y + param[0] > csbi.srWindow.Bottom) {
5280: clear_scr_buffer(csbi.wAttributes);
5281: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5282: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5283: } else {
1.1.1.14 root 5284: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5285: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5286: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5287: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5288: clear_scr_buffer(csbi.wAttributes);
1.1 root 5289: }
5290: co.X = 0;
5291: } else if(data == 'h') {
5292: if(tmp[2] == '>' && tmp[3] == '5') {
5293: CONSOLE_CURSOR_INFO cur;
5294: GetConsoleCursorInfo(hStdout, &cur);
5295: if(cur.bVisible) {
5296: cur.bVisible = FALSE;
1.1.1.14 root 5297: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5298: }
5299: }
5300: } else if(data == 'l') {
5301: if(tmp[2] == '>' && tmp[3] == '5') {
5302: CONSOLE_CURSOR_INFO cur;
5303: GetConsoleCursorInfo(hStdout, &cur);
5304: if(!cur.bVisible) {
5305: cur.bVisible = TRUE;
1.1.1.14 root 5306: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5307: }
5308: }
5309: } else if(data == 'm') {
5310: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
5311: int reverse = 0, hidden = 0;
5312: for(int i = 0; i < params; i++) {
5313: if(param[i] == 1) {
5314: wAttributes |= FOREGROUND_INTENSITY;
5315: } else if(param[i] == 4) {
5316: wAttributes |= COMMON_LVB_UNDERSCORE;
5317: } else if(param[i] == 7) {
5318: reverse = 1;
5319: } else if(param[i] == 8 || param[i] == 16) {
5320: hidden = 1;
5321: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
5322: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
5323: if(param[i] >= 17 && param[i] <= 23) {
5324: param[i] -= 16;
5325: } else {
5326: param[i] -= 30;
5327: }
5328: if(param[i] & 1) {
5329: wAttributes |= FOREGROUND_RED;
5330: }
5331: if(param[i] & 2) {
5332: wAttributes |= FOREGROUND_GREEN;
5333: }
5334: if(param[i] & 4) {
5335: wAttributes |= FOREGROUND_BLUE;
5336: }
5337: } else if(param[i] >= 40 && param[i] <= 47) {
5338: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
5339: if((param[i] - 40) & 1) {
5340: wAttributes |= BACKGROUND_RED;
5341: }
5342: if((param[i] - 40) & 2) {
5343: wAttributes |= BACKGROUND_GREEN;
5344: }
5345: if((param[i] - 40) & 4) {
5346: wAttributes |= BACKGROUND_BLUE;
5347: }
5348: }
5349: }
5350: if(reverse) {
5351: wAttributes &= ~0xff;
5352: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
5353: }
5354: if(hidden) {
5355: wAttributes &= ~0x0f;
5356: wAttributes |= (wAttributes >> 4) & 0x0f;
5357: }
5358: } else if(data == 'n') {
5359: if(param[0] == 6) {
5360: char tmp[16];
5361: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
5362: int len = strlen(tmp);
1.1.1.32 root 5363: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 5364: #ifdef USE_SERVICE_THREAD
5365: EnterCriticalSection(&key_buf_crit_sect);
5366: #endif
1.1.1.32 root 5367: for(int i = 0; i < len; i++) {
1.1.1.51 root 5368: pcbios_set_key_buffer(tmp[i], 0x00);
1.1.1.32 root 5369: }
1.1.1.35 root 5370: #ifdef USE_SERVICE_THREAD
5371: LeaveCriticalSection(&key_buf_crit_sect);
5372: #endif
1.1 root 5373: }
5374: }
5375: } else if(data == 's') {
5376: stored_x = co.X;
5377: stored_y = co.Y;
5378: stored_a = wAttributes;
5379: } else if(data == 'u') {
5380: co.X = stored_x;
5381: co.Y = stored_y;
5382: wAttributes = stored_a;
5383: }
5384: }
5385: if(co.X < 0) {
5386: co.X = 0;
5387: } else if(co.X >= csbi.dwSize.X) {
5388: co.X = csbi.dwSize.X - 1;
5389: }
1.1.1.14 root 5390: if(co.Y < csbi.srWindow.Top) {
5391: co.Y = csbi.srWindow.Top;
5392: } else if(co.Y > csbi.srWindow.Bottom) {
5393: co.Y = csbi.srWindow.Bottom;
1.1 root 5394: }
5395: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
5396: SetConsoleCursorPosition(hStdout, co);
5397: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5398: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 5399: cursor_moved = false;
5400: }
5401: if(wAttributes != csbi.wAttributes) {
5402: SetConsoleTextAttribute(hStdout, wAttributes);
5403: }
5404: p = is_esc = 0;
5405: }
5406: return;
5407: } else {
5408: if(msdos_lead_byte_check(data)) {
5409: is_kanji = 1;
5410: return;
5411: } else if(data == 0x1b) {
5412: is_esc = 1;
5413: return;
5414: }
5415: }
1.1.1.20 root 5416:
5417: DWORD q = 0, num;
5418: is_kanji = 0;
5419: for(int i = 0; i < p; i++) {
5420: UINT8 c = tmp[i];
5421: if(is_kanji) {
5422: is_kanji = 0;
5423: } else if(msdos_lead_byte_check(data)) {
5424: is_kanji = 1;
5425: } else if(msdos_ctrl_code_check(data)) {
5426: out[q++] = '^';
5427: c += 'A' - 1;
5428: }
5429: out[q++] = c;
5430: }
1.1.1.34 root 5431: if(q == 1 && out[0] == 0x08) {
5432: // back space
5433: GetConsoleScreenBufferInfo(hStdout, &csbi);
5434: if(csbi.dwCursorPosition.X > 0) {
5435: co.X = csbi.dwCursorPosition.X - 1;
5436: co.Y = csbi.dwCursorPosition.Y;
5437: SetConsoleCursorPosition(hStdout, co);
5438: } else if(csbi.dwCursorPosition.Y > 0) {
5439: co.X = csbi.dwSize.X - 1;
5440: co.Y = csbi.dwCursorPosition.Y - 1;
5441: SetConsoleCursorPosition(hStdout, co);
5442: } else {
5443: WriteConsole(hStdout, out, q, &num, NULL); // to make sure
5444: }
5445: } else {
5446: WriteConsole(hStdout, out, q, &num, NULL);
5447: }
1.1 root 5448: p = 0;
1.1.1.14 root 5449:
1.1.1.15 root 5450: if(!restore_console_on_exit) {
5451: GetConsoleScreenBufferInfo(hStdout, &csbi);
5452: scr_top = csbi.srWindow.Top;
5453: }
1.1 root 5454: cursor_moved = true;
5455: }
5456:
5457: int msdos_aux_in()
5458: {
1.1.1.21 root 5459: msdos_stdio_reopen();
5460:
1.1.1.20 root 5461: process_t *process = msdos_process_info_get(current_psp);
5462: int fd = msdos_psp_get_file_table(3, current_psp);
5463:
5464: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 5465: char data = 0;
1.1.1.37 root 5466: msdos_read(fd, &data, 1);
1.1 root 5467: return(data);
5468: } else {
5469: return(EOF);
5470: }
5471: }
5472:
5473: void msdos_aux_out(char data)
5474: {
1.1.1.21 root 5475: msdos_stdio_reopen();
5476:
1.1.1.20 root 5477: process_t *process = msdos_process_info_get(current_psp);
5478: int fd = msdos_psp_get_file_table(3, current_psp);
5479:
5480: if(fd < process->max_files && file_handler[fd].valid) {
5481: msdos_write(fd, &data, 1);
1.1 root 5482: }
5483: }
5484:
5485: void msdos_prn_out(char data)
5486: {
1.1.1.21 root 5487: msdos_stdio_reopen();
5488:
1.1.1.20 root 5489: process_t *process = msdos_process_info_get(current_psp);
5490: int fd = msdos_psp_get_file_table(4, current_psp);
5491:
5492: if(fd < process->max_files && file_handler[fd].valid) {
5493: msdos_write(fd, &data, 1);
1.1 root 5494: }
5495: }
5496:
5497: // memory control
5498:
1.1.1.52 root 5499: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs, const char *prog_name = NULL)
1.1 root 5500: {
5501: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5502:
5503: mcb->mz = mz;
5504: mcb->psp = psp;
1.1.1.30 root 5505: mcb->paragraphs = paragraphs;
1.1.1.39 root 5506:
5507: if(prog_name != NULL) {
5508: memset(mcb->prog_name, 0, 8);
5509: memcpy(mcb->prog_name, prog_name, min(8, strlen(prog_name)));
5510: }
1.1 root 5511: return(mcb);
5512: }
5513:
5514: void msdos_mcb_check(mcb_t *mcb)
5515: {
5516: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 5517: #if 0
5518: // shutdown now !!!
5519: fatalerror("broken memory control block\n");
5520: #else
5521: // return error code and continue
5522: throw(0x07); // broken memory control block
5523: #endif
1.1 root 5524: }
5525: }
5526:
1.1.1.39 root 5527: void msdos_mem_split(int seg, int paragraphs)
1.1 root 5528: {
5529: int mcb_seg = seg - 1;
5530: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5531: msdos_mcb_check(mcb);
5532:
1.1.1.30 root 5533: if(mcb->paragraphs > paragraphs) {
1.1 root 5534: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 5535: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 5536:
5537: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5538: mcb->mz = 'M';
1.1.1.30 root 5539: mcb->paragraphs = paragraphs;
1.1 root 5540: }
5541: }
5542:
5543: void msdos_mem_merge(int seg)
5544: {
5545: int mcb_seg = seg - 1;
5546: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5547: msdos_mcb_check(mcb);
5548:
5549: while(1) {
5550: if(mcb->mz == 'Z') {
5551: break;
5552: }
1.1.1.30 root 5553: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 5554: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5555: msdos_mcb_check(next_mcb);
5556:
5557: if(next_mcb->psp != 0) {
5558: break;
5559: }
5560: mcb->mz = next_mcb->mz;
1.1.1.30 root 5561: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 5562: }
5563: }
5564:
1.1.1.8 root 5565: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 5566: {
5567: while(1) {
5568: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5569: bool last_block;
1.1 root 5570:
1.1.1.14 root 5571: if(mcb->psp == 0) {
5572: msdos_mem_merge(mcb_seg + 1);
5573: } else {
5574: msdos_mcb_check(mcb);
5575: }
1.1.1.33 root 5576: if(!(last_block = (mcb->mz == 'Z'))) {
5577: // check if the next is dummy mcb to link to umb
5578: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5579: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5580: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5581: }
5582: if(!(new_process && !last_block)) {
1.1.1.30 root 5583: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 5584: msdos_mem_split(mcb_seg + 1, paragraphs);
5585: mcb->psp = current_psp;
5586: return(mcb_seg + 1);
5587: }
5588: }
5589: if(mcb->mz == 'Z') {
5590: break;
5591: }
1.1.1.30 root 5592: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5593: }
5594: return(-1);
5595: }
5596:
5597: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5598: {
5599: int mcb_seg = seg - 1;
5600: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5601: msdos_mcb_check(mcb);
1.1.1.30 root 5602: int current_paragraphs = mcb->paragraphs;
1.1 root 5603:
5604: msdos_mem_merge(seg);
1.1.1.30 root 5605: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 5606: if(max_paragraphs) {
1.1.1.30 root 5607: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 5608: }
1.1 root 5609: msdos_mem_split(seg, current_paragraphs);
5610: return(-1);
5611: }
5612: msdos_mem_split(seg, paragraphs);
5613: return(0);
5614: }
5615:
5616: void msdos_mem_free(int seg)
5617: {
5618: int mcb_seg = seg - 1;
5619: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5620: msdos_mcb_check(mcb);
5621:
5622: mcb->psp = 0;
5623: msdos_mem_merge(seg);
5624: }
5625:
1.1.1.8 root 5626: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 5627: {
5628: int max_paragraphs = 0;
5629:
5630: while(1) {
5631: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5632: bool last_block;
5633:
1.1 root 5634: msdos_mcb_check(mcb);
5635:
1.1.1.33 root 5636: if(!(last_block = (mcb->mz == 'Z'))) {
5637: // check if the next is dummy mcb to link to umb
5638: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5639: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5640: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5641: }
5642: if(!(new_process && !last_block)) {
1.1.1.30 root 5643: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
5644: max_paragraphs = mcb->paragraphs;
1.1 root 5645: }
5646: }
5647: if(mcb->mz == 'Z') {
5648: break;
5649: }
1.1.1.30 root 5650: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5651: }
1.1.1.14 root 5652: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 5653: }
5654:
1.1.1.8 root 5655: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
5656: {
5657: int last_seg = -1;
5658:
5659: while(1) {
5660: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5661: msdos_mcb_check(mcb);
5662:
1.1.1.14 root 5663: if(mcb->psp == psp) {
1.1.1.8 root 5664: last_seg = mcb_seg;
5665: }
1.1.1.14 root 5666: if(mcb->mz == 'Z') {
5667: break;
5668: }
1.1.1.30 root 5669: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 5670: }
5671: return(last_seg);
5672: }
5673:
1.1.1.19 root 5674: int msdos_mem_get_umb_linked()
5675: {
1.1.1.33 root 5676: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5677: msdos_mcb_check(mcb);
1.1.1.19 root 5678:
1.1.1.33 root 5679: if(mcb->mz == 'M') {
5680: return(-1);
1.1.1.19 root 5681: }
5682: return(0);
5683: }
5684:
1.1.1.33 root 5685: void msdos_mem_link_umb()
1.1.1.19 root 5686: {
1.1.1.33 root 5687: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5688: msdos_mcb_check(mcb);
1.1.1.19 root 5689:
1.1.1.33 root 5690: mcb->mz = 'M';
5691: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
1.1.1.39 root 5692:
5693: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 5694: }
5695:
1.1.1.33 root 5696: void msdos_mem_unlink_umb()
1.1.1.19 root 5697: {
1.1.1.33 root 5698: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5699: msdos_mcb_check(mcb);
1.1.1.19 root 5700:
1.1.1.33 root 5701: mcb->mz = 'Z';
5702: mcb->paragraphs = 0;
1.1.1.39 root 5703:
5704: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 5705: }
5706:
1.1.1.29 root 5707: #ifdef SUPPORT_HMA
5708:
5709: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
5710: {
5711: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5712:
5713: mcb->ms[0] = 'M';
5714: mcb->ms[1] = 'S';
5715: mcb->owner = owner;
5716: mcb->size = size;
5717: mcb->next = next;
5718: return(mcb);
5719: }
5720:
5721: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
5722: {
5723: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
5724: }
5725:
5726: int msdos_hma_mem_split(int offset, int size)
5727: {
5728: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5729:
5730: if(!msdos_is_hma_mcb_valid(mcb)) {
5731: return(-1);
5732: }
5733: if(mcb->size >= size + 0x10) {
5734: int new_offset = offset + 0x10 + size;
5735: int new_size = mcb->size - 0x10 - size;
5736:
5737: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
5738: mcb->size = size;
5739: mcb->next = new_offset;
5740: return(0);
5741: }
5742: return(-1);
5743: }
5744:
5745: void msdos_hma_mem_merge(int offset)
5746: {
5747: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5748:
5749: if(!msdos_is_hma_mcb_valid(mcb)) {
5750: return;
5751: }
5752: while(1) {
5753: if(mcb->next == 0) {
5754: break;
5755: }
5756: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
5757:
5758: if(!msdos_is_hma_mcb_valid(next_mcb)) {
5759: return;
5760: }
5761: if(next_mcb->owner != 0) {
5762: break;
5763: }
5764: mcb->size += 0x10 + next_mcb->size;
5765: mcb->next = next_mcb->next;
5766: }
5767: }
5768:
5769: int msdos_hma_mem_alloc(int size, UINT16 owner)
5770: {
5771: int offset = 0x10; // first mcb in HMA
5772:
5773: while(1) {
5774: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5775:
5776: if(!msdos_is_hma_mcb_valid(mcb)) {
5777: return(-1);
5778: }
5779: if(mcb->owner == 0) {
5780: msdos_hma_mem_merge(offset);
5781: }
5782: if(mcb->owner == 0 && mcb->size >= size) {
5783: msdos_hma_mem_split(offset, size);
5784: mcb->owner = owner;
5785: return(offset);
5786: }
5787: if(mcb->next == 0) {
5788: break;
5789: }
5790: offset = mcb->next;
5791: }
5792: return(-1);
5793: }
5794:
5795: int msdos_hma_mem_realloc(int offset, int size)
5796: {
5797: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5798:
5799: if(!msdos_is_hma_mcb_valid(mcb)) {
5800: return(-1);
5801: }
5802: if(mcb->size < size) {
5803: return(-1);
5804: }
5805: msdos_hma_mem_split(offset, size);
5806: return(0);
5807: }
5808:
5809: void msdos_hma_mem_free(int offset)
5810: {
5811: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5812:
5813: if(!msdos_is_hma_mcb_valid(mcb)) {
5814: return;
5815: }
5816: mcb->owner = 0;
5817: msdos_hma_mem_merge(offset);
5818: }
5819:
5820: int msdos_hma_mem_get_free(int *available_offset)
5821: {
5822: int offset = 0x10; // first mcb in HMA
5823: int size = 0;
5824:
5825: while(1) {
5826: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5827:
5828: if(!msdos_is_hma_mcb_valid(mcb)) {
5829: return(0);
5830: }
5831: if(mcb->owner == 0 && size < mcb->size) {
5832: if(available_offset != NULL) {
5833: *available_offset = offset;
5834: }
5835: size = mcb->size;
5836: }
5837: if(mcb->next == 0) {
5838: break;
5839: }
5840: offset = mcb->next;
5841: }
5842: return(size);
5843: }
5844:
5845: #endif
5846:
1.1 root 5847: // environment
5848:
1.1.1.45 root 5849: void msdos_env_set_argv(int env_seg, const char *argv)
1.1 root 5850: {
5851: char *dst = (char *)(mem + (env_seg << 4));
5852:
5853: while(1) {
5854: if(dst[0] == 0) {
5855: break;
5856: }
5857: dst += strlen(dst) + 1;
5858: }
5859: *dst++ = 0; // end of environment
5860: *dst++ = 1; // top of argv[0]
5861: *dst++ = 0;
5862: memcpy(dst, argv, strlen(argv));
5863: dst += strlen(argv);
5864: *dst++ = 0;
5865: *dst++ = 0;
5866: }
5867:
1.1.1.45 root 5868: const char *msdos_env_get_argv(int env_seg)
1.1 root 5869: {
5870: static char env[ENV_SIZE];
5871: char *src = env;
5872:
5873: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5874: while(1) {
5875: if(src[0] == 0) {
5876: if(src[1] == 1) {
5877: return(src + 3);
5878: }
5879: break;
5880: }
5881: src += strlen(src) + 1;
5882: }
5883: return(NULL);
5884: }
5885:
1.1.1.45 root 5886: const char *msdos_env_get(int env_seg, const char *name)
1.1 root 5887: {
5888: static char env[ENV_SIZE];
5889: char *src = env;
5890:
5891: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5892: while(1) {
5893: if(src[0] == 0) {
5894: break;
5895: }
5896: int len = strlen(src);
5897: char *n = my_strtok(src, "=");
5898: char *v = src + strlen(n) + 1;
5899:
5900: if(_stricmp(name, n) == 0) {
5901: return(v);
5902: }
5903: src += len + 1;
5904: }
5905: return(NULL);
5906: }
5907:
1.1.1.45 root 5908: void msdos_env_set(int env_seg, const char *name, const char *value)
1.1 root 5909: {
5910: char env[ENV_SIZE];
5911: char *src = env;
5912: char *dst = (char *)(mem + (env_seg << 4));
1.1.1.45 root 5913: const char *argv = msdos_env_get_argv(env_seg);
1.1 root 5914: int done = 0;
5915:
5916: memcpy(src, dst, ENV_SIZE);
5917: memset(dst, 0, ENV_SIZE);
5918: while(1) {
5919: if(src[0] == 0) {
5920: break;
5921: }
5922: int len = strlen(src);
5923: char *n = my_strtok(src, "=");
5924: char *v = src + strlen(n) + 1;
5925: char tmp[1024];
5926:
5927: if(_stricmp(name, n) == 0) {
5928: sprintf(tmp, "%s=%s", n, value);
5929: done = 1;
5930: } else {
5931: sprintf(tmp, "%s=%s", n, v);
5932: }
5933: memcpy(dst, tmp, strlen(tmp));
5934: dst += strlen(tmp) + 1;
5935: src += len + 1;
5936: }
5937: if(!done) {
5938: char tmp[1024];
5939:
5940: sprintf(tmp, "%s=%s", name, value);
5941: memcpy(dst, tmp, strlen(tmp));
5942: dst += strlen(tmp) + 1;
5943: }
5944: if(argv) {
5945: *dst++ = 0; // end of environment
5946: *dst++ = 1; // top of argv[0]
5947: *dst++ = 0;
5948: memcpy(dst, argv, strlen(argv));
5949: dst += strlen(argv);
5950: *dst++ = 0;
5951: *dst++ = 0;
5952: }
5953: }
5954:
5955: // process
5956:
1.1.1.8 root 5957: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 5958: {
5959: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5960:
5961: memset(psp, 0, PSP_SIZE);
5962: psp->exit[0] = 0xcd;
5963: psp->exit[1] = 0x20;
1.1.1.8 root 5964: psp->first_mcb = mcb_seg;
1.1.1.46 root 5965: #if 1
1.1.1.49 root 5966: psp->call5[0] = 0xcd; // int 30h
5967: psp->call5[1] = 0x30;
1.1.1.46 root 5968: psp->call5[2] = 0xc3; // ret
5969: #else
5970: psp->call5[0] = 0x8a; // mov ah, cl
5971: psp->call5[1] = 0xe1;
5972: psp->call5[2] = 0xcd; // int 21h
5973: psp->call5[3] = 0x21;
5974: psp->call5[4] = 0xc3; // ret
5975: #endif
1.1 root 5976: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5977: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5978: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5979: psp->parent_psp = parent_psp;
1.1.1.20 root 5980: if(parent_psp == (UINT16)-1) {
5981: for(int i = 0; i < 20; i++) {
5982: if(file_handler[i].valid) {
5983: psp->file_table[i] = i;
5984: } else {
5985: psp->file_table[i] = 0xff;
5986: }
1.1 root 5987: }
1.1.1.20 root 5988: } else {
5989: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 5990: }
5991: psp->env_seg = env_seg;
5992: psp->stack.w.l = REG16(SP);
1.1.1.3 root 5993: psp->stack.w.h = SREG(SS);
1.1.1.14 root 5994: psp->file_table_size = 20;
5995: psp->file_table_ptr.w.l = 0x18;
5996: psp->file_table_ptr.w.h = psp_seg;
1.1 root 5997: psp->service[0] = 0xcd;
5998: psp->service[1] = 0x21;
5999: psp->service[2] = 0xcb;
6000: return(psp);
6001: }
6002:
1.1.1.20 root 6003: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
6004: {
6005: if(psp_seg && fd < 20) {
6006: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6007: psp->file_table[fd] = value;
6008: }
6009: }
6010:
6011: int msdos_psp_get_file_table(int fd, int psp_seg)
6012: {
6013: if(psp_seg && fd < 20) {
6014: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6015: fd = psp->file_table[fd];
6016: }
6017: return fd;
6018: }
6019:
1.1.1.52 root 6020: int msdos_process_exec(const char *cmd, param_block_t *param, UINT8 al, bool first_process = false)
1.1 root 6021: {
6022: // load command file
6023: int fd = -1;
1.1.1.45 root 6024: int sio_port = 0;
6025: int lpt_port = 0;
1.1 root 6026: int dos_command = 0;
1.1.1.24 root 6027: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1.1.38 root 6028: char pipe_stdin_path[MAX_PATH] = {0};
6029: char pipe_stdout_path[MAX_PATH] = {0};
1.1.1.39 root 6030: char pipe_stderr_path[MAX_PATH] = {0};
1.1 root 6031:
6032: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
6033: int opt_len = mem[opt_ofs];
6034: memset(opt, 0, sizeof(opt));
6035: memcpy(opt, mem + opt_ofs + 1, opt_len);
6036:
1.1.1.14 root 6037: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
6038: // this is a batch file, run command.com
6039: char tmp[MAX_PATH];
6040: if(opt_len != 0) {
6041: sprintf(tmp, "/C %s %s", cmd, opt);
6042: } else {
6043: sprintf(tmp, "/C %s", cmd);
6044: }
6045: strcpy(opt, tmp);
6046: opt_len = strlen(opt);
6047: mem[opt_ofs] = opt_len;
6048: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6049: strcpy(command, comspec_path);
6050: strcpy(name_tmp, "COMMAND.COM");
6051: } else {
6052: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
6053: // redirect C:\COMMAND.COM to comspec_path
6054: strcpy(command, comspec_path);
6055: } else {
6056: strcpy(command, cmd);
6057: }
1.1.1.24 root 6058: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
6059: return(-1);
6060: }
1.1.1.14 root 6061: memset(name_tmp, 0, sizeof(name_tmp));
6062: strcpy(name_tmp, name);
6063:
6064: // check command.com
1.1.1.38 root 6065: if((_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) && _access(comspec_path, 0) != 0) {
6066: // we can not load command.com, so run program directly if "command /c (program)" is specified
1.1.1.14 root 6067: if(opt_len == 0) {
6068: // process_t *current_process = msdos_process_info_get(current_psp);
6069: process_t *current_process = NULL;
6070: for(int i = 0; i < MAX_PROCESS; i++) {
6071: if(process[i].psp == current_psp) {
6072: current_process = &process[i];
6073: break;
6074: }
6075: }
6076: if(current_process != NULL) {
6077: param->cmd_line.dw = current_process->dta.dw;
6078: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
6079: opt_len = mem[opt_ofs];
6080: memset(opt, 0, sizeof(opt));
6081: memcpy(opt, mem + opt_ofs + 1, opt_len);
6082: }
6083: }
6084: for(int i = 0; i < opt_len; i++) {
6085: if(opt[i] == ' ') {
6086: continue;
6087: }
6088: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
6089: for(int j = i + 3; j < opt_len; j++) {
6090: if(opt[j] == ' ') {
6091: continue;
6092: }
6093: char *token = my_strtok(opt + j, " ");
6094:
1.1.1.38 root 6095: strcpy(command, token);
6096: char tmp[MAX_PATH];
6097: strcpy(tmp, token + strlen(token) + 1);
1.1.1.39 root 6098: strcpy(opt, "");
6099: for(int i = 0; i < strlen(tmp); i++) {
6100: if(tmp[i] != ' ') {
6101: strcpy(opt, tmp + i);
6102: break;
6103: }
6104: }
6105: strcpy(tmp, opt);
1.1.1.38 root 6106:
6107: if(al == 0x00) {
1.1.1.39 root 6108: #define GET_FILE_PATH() { \
6109: if(token[0] != '>' && token[0] != '<') { \
6110: token++; \
6111: } \
6112: token++; \
6113: while(*token == ' ') { \
6114: token++; \
6115: } \
6116: char *ptr = token; \
6117: while(*ptr != ' ' && *ptr != '\r' && *ptr != '\0') { \
6118: ptr++; \
6119: } \
6120: *ptr = '\0'; \
6121: }
6122: if((token = strstr(opt, "0<")) != NULL || (token = strstr(opt, "<")) != NULL) {
6123: GET_FILE_PATH();
1.1.1.38 root 6124: strcpy(pipe_stdin_path, token);
6125: strcpy(opt, tmp);
6126: }
1.1.1.39 root 6127: if((token = strstr(opt, "1>")) != NULL || (token = strstr(opt, ">")) != NULL) {
6128: GET_FILE_PATH();
1.1.1.38 root 6129: strcpy(pipe_stdout_path, token);
6130: strcpy(opt, tmp);
6131: }
1.1.1.39 root 6132: if((token = strstr(opt, "2>")) != NULL) {
6133: GET_FILE_PATH();
6134: strcpy(pipe_stderr_path, token);
6135: strcpy(opt, tmp);
6136: }
6137: #undef GET_FILE_PATH
6138:
6139: if((token = strstr(opt, "0<")) != NULL) {
6140: *token = '\0';
6141: }
6142: if((token = strstr(opt, "1>")) != NULL) {
6143: *token = '\0';
6144: }
6145: if((token = strstr(opt, "2>")) != NULL) {
6146: *token = '\0';
6147: }
1.1.1.38 root 6148: if((token = strstr(opt, "<")) != NULL) {
6149: *token = '\0';
6150: }
6151: if((token = strstr(opt, ">")) != NULL) {
6152: *token = '\0';
6153: }
1.1.1.14 root 6154: }
1.1.1.39 root 6155: for(int i = strlen(opt) - 1; i >= 0 && opt[i] == ' '; i--) {
6156: opt[i] = '\0';
6157: }
1.1.1.38 root 6158: opt_len = strlen(opt);
6159: mem[opt_ofs] = opt_len;
6160: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6161: dos_command = 1;
1.1.1.14 root 6162: break;
1.1 root 6163: }
6164: }
1.1.1.14 root 6165: break;
1.1 root 6166: }
6167: }
6168: }
6169:
6170: // load command file
6171: strcpy(path, command);
6172: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
6173: sprintf(path, "%s.COM", command);
6174: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
6175: sprintf(path, "%s.EXE", command);
6176: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 6177: sprintf(path, "%s.BAT", command);
6178: if(_access(path, 0) == 0) {
6179: // this is a batch file, run command.com
6180: char tmp[MAX_PATH];
6181: if(opt_len != 0) {
6182: sprintf(tmp, "/C %s %s", path, opt);
6183: } else {
6184: sprintf(tmp, "/C %s", path);
6185: }
6186: strcpy(opt, tmp);
6187: opt_len = strlen(opt);
6188: mem[opt_ofs] = opt_len;
6189: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6190: strcpy(path, comspec_path);
6191: strcpy(name_tmp, "COMMAND.COM");
6192: fd = _open(path, _O_RDONLY | _O_BINARY);
6193: } else {
6194: // search path in parent environments
6195: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
1.1.1.45 root 6196: const char *env = msdos_env_get(parent_psp->env_seg, "PATH");
1.1.1.14 root 6197: if(env != NULL) {
6198: char env_path[4096];
6199: strcpy(env_path, env);
6200: char *token = my_strtok(env_path, ";");
6201:
6202: while(token != NULL) {
6203: if(strlen(token) != 0) {
6204: sprintf(path, "%s", msdos_combine_path(token, command));
6205: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6206: break;
6207: }
6208: sprintf(path, "%s.COM", msdos_combine_path(token, command));
6209: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6210: break;
6211: }
6212: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
6213: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6214: break;
6215: }
6216: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
6217: if(_access(path, 0) == 0) {
6218: // this is a batch file, run command.com
6219: char tmp[MAX_PATH];
6220: if(opt_len != 0) {
6221: sprintf(tmp, "/C %s %s", path, opt);
6222: } else {
6223: sprintf(tmp, "/C %s", path);
6224: }
6225: strcpy(opt, tmp);
6226: opt_len = strlen(opt);
6227: mem[opt_ofs] = opt_len;
6228: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6229: strcpy(path, comspec_path);
6230: strcpy(name_tmp, "COMMAND.COM");
6231: fd = _open(path, _O_RDONLY | _O_BINARY);
6232: break;
6233: }
1.1.1.8 root 6234: }
1.1.1.14 root 6235: token = my_strtok(NULL, ";");
1.1 root 6236: }
6237: }
6238: }
6239: }
6240: }
6241: }
6242: if(fd == -1) {
1.1.1.38 root 6243: // we can not find command.com in the path, so open comspec_path
6244: if(_stricmp(command, "COMMAND.COM") == 0 || _stricmp(command, "COMMAND") == 0) {
6245: strcpy(command, comspec_path);
6246: strcpy(path, command);
6247: fd = _open(path, _O_RDONLY | _O_BINARY);
6248: }
6249: }
6250: if(fd == -1) {
1.1.1.52 root 6251: if(!first_process && al == 0 && dos_command) {
1.1 root 6252: // may be dos command
6253: char tmp[MAX_PATH];
1.1.1.52 root 6254: if(opt_len != 0) {
6255: sprintf(tmp, "%s %s", command, opt);
6256: } else {
6257: sprintf(tmp, "%s", command);
6258: }
6259: retval = system(tmp);
1.1 root 6260: return(0);
6261: } else {
6262: return(-1);
6263: }
6264: }
1.1.1.52 root 6265: memset(file_buffer, 0, sizeof(file_buffer));
1.1 root 6266: _read(fd, file_buffer, sizeof(file_buffer));
6267: _close(fd);
6268:
1.1.1.52 root 6269: // check if this is win32 program
6270: if(!first_process && al == 0) {
6271: UINT16 sign_dos = *(UINT16 *)(file_buffer + 0x00);
6272: UINT32 e_lfanew = *(UINT32 *)(file_buffer + 0x3c);
6273: if(sign_dos == IMAGE_DOS_SIGNATURE && e_lfanew >= 0x40 && e_lfanew < 0x400) {
6274: UINT32 sign_nt = *(UINT32 *)(file_buffer + e_lfanew + 0x00);
6275: UINT16 machine = *(UINT16 *)(file_buffer + e_lfanew + 0x04);
6276: if(sign_nt == IMAGE_NT_SIGNATURE && (machine == IMAGE_FILE_MACHINE_I386 || machine == IMAGE_FILE_MACHINE_AMD64)) {
6277: char tmp[MAX_PATH];
6278: if(opt_len != 0) {
6279: sprintf(tmp, "\"%s\" %s", path, opt);
6280: } else {
6281: sprintf(tmp, "\"%s\"", path);
6282: }
6283: retval = system(tmp);
6284: return(0);
6285: }
6286: }
6287: }
6288:
1.1 root 6289: // copy environment
1.1.1.29 root 6290: int umb_linked, env_seg, psp_seg;
1.1 root 6291:
1.1.1.29 root 6292: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6293: msdos_mem_unlink_umb();
6294: }
1.1.1.8 root 6295: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 6296: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
6297: if(umb_linked != 0) {
6298: msdos_mem_link_umb();
6299: }
6300: return(-1);
6301: }
1.1 root 6302: }
6303: if(param->env_seg == 0) {
6304: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
6305: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
6306: } else {
6307: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
6308: }
6309: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
6310:
6311: // check exe header
6312: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 6313: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 6314: UINT16 cs, ss, ip, sp;
6315:
6316: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6317: // memory allocation
6318: int header_size = header->header_size * 16;
6319: int load_size = header->pages * 512 - header_size;
6320: if(header_size + load_size < 512) {
6321: load_size = 512 - header_size;
6322: }
6323: paragraphs = (PSP_SIZE + load_size) >> 4;
6324: if(paragraphs + header->min_alloc > free_paragraphs) {
6325: msdos_mem_free(env_seg);
6326: return(-1);
6327: }
6328: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
6329: if(paragraphs > free_paragraphs) {
6330: paragraphs = free_paragraphs;
6331: }
1.1.1.8 root 6332: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6333: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6334: if(umb_linked != 0) {
6335: msdos_mem_link_umb();
6336: }
6337: msdos_mem_free(env_seg);
6338: return(-1);
6339: }
1.1 root 6340: }
6341: // relocation
6342: int start_seg = psp_seg + (PSP_SIZE >> 4);
6343: for(int i = 0; i < header->relocations; i++) {
6344: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6345: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6346: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6347: }
6348: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
6349: // segments
6350: cs = header->init_cs + start_seg;
6351: ss = header->init_ss + start_seg;
6352: ip = header->init_ip;
6353: sp = header->init_sp - 2; // for symdeb
6354: } else {
6355: // memory allocation
6356: paragraphs = free_paragraphs;
1.1.1.8 root 6357: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6358: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6359: if(umb_linked != 0) {
6360: msdos_mem_link_umb();
6361: }
6362: msdos_mem_free(env_seg);
6363: return(-1);
6364: }
1.1 root 6365: }
6366: int start_seg = psp_seg + (PSP_SIZE >> 4);
6367: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
6368: // segments
6369: cs = ss = psp_seg;
6370: ip = 0x100;
6371: sp = 0xfffe;
6372: }
1.1.1.29 root 6373: if(umb_linked != 0) {
6374: msdos_mem_link_umb();
6375: }
1.1 root 6376:
6377: // create psp
1.1.1.3 root 6378: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
6379: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 6380: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
6381: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
6382: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
6383: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
6384:
6385: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
6386: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
6387: mcb_psp->psp = mcb_env->psp = psp_seg;
6388:
1.1.1.4 root 6389: for(int i = 0; i < 8; i++) {
6390: if(name_tmp[i] == '.') {
6391: mcb_psp->prog_name[i] = '\0';
6392: break;
6393: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
6394: mcb_psp->prog_name[i] = name_tmp[i];
6395: i++;
6396: mcb_psp->prog_name[i] = name_tmp[i];
6397: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
6398: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
6399: } else {
6400: mcb_psp->prog_name[i] = name_tmp[i];
6401: }
6402: }
6403:
1.1 root 6404: // process info
6405: process_t *process = msdos_process_info_create(psp_seg);
6406: strcpy(process->module_dir, msdos_short_full_dir(path));
1.1.1.33 root 6407: #ifdef USE_DEBUGGER
6408: strcpy(process->module_path, path);
6409: #endif
1.1 root 6410: process->dta.w.l = 0x80;
6411: process->dta.w.h = psp_seg;
6412: process->switchar = '/';
6413: process->max_files = 20;
6414: process->parent_int_10h_feh_called = int_10h_feh_called;
6415: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 6416: process->parent_ds = SREG(DS);
1.1.1.31 root 6417: process->parent_es = SREG(ES);
1.1 root 6418:
6419: current_psp = psp_seg;
1.1.1.23 root 6420: msdos_sda_update(current_psp);
1.1 root 6421:
6422: if(al == 0x00) {
6423: int_10h_feh_called = int_10h_ffh_called = false;
6424:
1.1.1.38 root 6425: // pipe
6426: if(pipe_stdin_path[0] != '\0') {
1.1.1.45 root 6427: // if((fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY)) != -1) {
6428: if(msdos_is_device_path(pipe_stdin_path)) {
6429: fd = msdos_open_device(pipe_stdin_path, _O_RDONLY | _O_BINARY, &sio_port, &lpt_port);
6430: } else {
6431: fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY);
6432: }
6433: if(fd != -1) {
6434: msdos_file_handler_open(fd, pipe_stdin_path, _isatty(fd), 0, msdos_device_info(pipe_stdin_path), current_psp, sio_port, lpt_port);
1.1.1.38 root 6435: psp->file_table[0] = fd;
6436: msdos_psp_set_file_table(fd, fd, current_psp);
6437: }
6438: }
6439: if(pipe_stdout_path[0] != '\0') {
6440: if(_access(pipe_stdout_path, 0) == 0) {
6441: SetFileAttributes(pipe_stdout_path, FILE_ATTRIBUTE_NORMAL);
6442: DeleteFile(pipe_stdout_path);
6443: }
1.1.1.45 root 6444: // if((fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) {
6445: if(msdos_is_device_path(pipe_stdout_path)) {
6446: fd = msdos_open_device(pipe_stdout_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
6447: } else {
6448: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6449: }
6450: if(fd != -1) {
6451: msdos_file_handler_open(fd, pipe_stdout_path, _isatty(fd), 1, msdos_device_info(pipe_stdout_path), current_psp, sio_port, lpt_port);
1.1.1.38 root 6452: psp->file_table[1] = fd;
6453: msdos_psp_set_file_table(fd, fd, current_psp);
6454: }
6455: }
1.1.1.39 root 6456: if(pipe_stderr_path[0] != '\0') {
6457: if(_access(pipe_stderr_path, 0) == 0) {
6458: SetFileAttributes(pipe_stderr_path, FILE_ATTRIBUTE_NORMAL);
6459: DeleteFile(pipe_stderr_path);
6460: }
1.1.1.45 root 6461: // if((fd = _open(pipe_stderr_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) {
6462: if(msdos_is_device_path(pipe_stderr_path)) {
6463: fd = msdos_open_device(pipe_stderr_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
6464: } else {
6465: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6466: }
6467: if(fd != -1) {
6468: msdos_file_handler_open(fd, pipe_stderr_path, _isatty(fd), 1, msdos_device_info(pipe_stderr_path), current_psp, sio_port, lpt_port);
1.1.1.39 root 6469: psp->file_table[2] = fd;
6470: msdos_psp_set_file_table(fd, fd, current_psp);
6471: }
6472: }
1.1.1.38 root 6473:
1.1 root 6474: // registers and segments
6475: REG16(AX) = REG16(BX) = 0x00;
6476: REG16(CX) = 0xff;
6477: REG16(DX) = psp_seg;
6478: REG16(SI) = ip;
6479: REG16(DI) = sp;
6480: REG16(SP) = sp;
1.1.1.3 root 6481: SREG(DS) = SREG(ES) = psp_seg;
6482: SREG(SS) = ss;
6483: i386_load_segment_descriptor(DS);
6484: i386_load_segment_descriptor(ES);
6485: i386_load_segment_descriptor(SS);
1.1 root 6486:
6487: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
6488: i386_jmp_far(cs, ip);
6489: } else if(al == 0x01) {
6490: // copy ss:sp and cs:ip to param block
6491: param->sp = sp;
6492: param->ss = ss;
6493: param->ip = ip;
6494: param->cs = cs;
1.1.1.31 root 6495:
6496: // the AX value to be passed to the child program is put on top of the child's stack
6497: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 6498: }
6499: return(0);
6500: }
6501:
6502: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
6503: {
6504: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6505:
6506: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
6507: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
6508: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
6509:
1.1.1.3 root 6510: SREG(SS) = psp->stack.w.h;
6511: i386_load_segment_descriptor(SS);
1.1 root 6512: REG16(SP) = psp->stack.w.l;
6513: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
6514:
1.1.1.28 root 6515: // process_t *current_process = msdos_process_info_get(psp_seg);
6516: process_t *current_process = NULL;
6517: for(int i = 0; i < MAX_PROCESS; i++) {
6518: if(process[i].psp == psp_seg) {
6519: current_process = &process[i];
6520: break;
6521: }
6522: }
6523: if(current_process == NULL) {
6524: throw(0x1f); // general failure
6525: }
6526: int_10h_feh_called = current_process->parent_int_10h_feh_called;
6527: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
6528: if(current_process->called_by_int2eh) {
6529: REG16(AX) = ret;
6530: }
6531: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 6532: SREG(ES) = current_process->parent_es;
1.1.1.14 root 6533: i386_load_segment_descriptor(DS);
1.1.1.31 root 6534: i386_load_segment_descriptor(ES);
1.1 root 6535:
6536: if(mem_free) {
1.1.1.8 root 6537: int mcb_seg;
6538: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
6539: msdos_mem_free(mcb_seg + 1);
6540: }
6541: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
6542: msdos_mem_free(mcb_seg + 1);
6543: }
1.1 root 6544:
6545: for(int i = 0; i < MAX_FILES; i++) {
6546: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
6547: _close(i);
1.1.1.20 root 6548: msdos_file_handler_close(i);
6549: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 6550: }
6551: }
1.1.1.13 root 6552: msdos_dta_info_free(psp_seg);
1.1 root 6553: }
1.1.1.14 root 6554: msdos_stdio_reopen();
1.1 root 6555:
1.1.1.28 root 6556: memset(current_process, 0, sizeof(process_t));
1.1 root 6557:
6558: current_psp = psp->parent_psp;
6559: retval = ret;
1.1.1.23 root 6560: msdos_sda_update(current_psp);
1.1 root 6561: }
6562:
6563: // drive
6564:
1.1.1.42 root 6565: int pcbios_update_drive_param(int drive_num, int force_update);
6566:
1.1 root 6567: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
6568: {
1.1.1.41 root 6569: if(!(drive_num >= 0 && drive_num < 26)) {
6570: return(0);
6571: }
1.1.1.42 root 6572: pcbios_update_drive_param(drive_num, force_update);
6573:
6574: drive_param_t *drive_param = &drive_params[drive_num];
1.1 root 6575: *seg = DPB_TOP >> 4;
6576: *ofs = sizeof(dpb_t) * drive_num;
6577: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
6578:
6579: memset(dpb, 0, sizeof(dpb_t));
6580:
1.1.1.41 root 6581: dpb->drive_num = drive_num;
6582: dpb->unit_num = drive_num;
1.1.1.42 root 6583:
6584: if(drive_param->valid) {
6585: DISK_GEOMETRY *geo = &drive_param->geometry;
6586:
6587: dpb->bytes_per_sector = (UINT16)geo->BytesPerSector;
6588: dpb->highest_sector_num = (UINT8)(geo->SectorsPerTrack - 1);
6589: dpb->highest_cluster_num = (UINT16)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6590: dpb->maximum_cluster_num = (UINT32)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6591: switch(geo->MediaType) {
6592: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6593: dpb->media_type = 0xff;
6594: break;
6595: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6596: dpb->media_type = 0xfe;
6597: break;
6598: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6599: dpb->media_type = 0xfd;
6600: break;
6601: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6602: dpb->media_type = 0xfc;
6603: break;
6604: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6605: case F3_1Pt2_512:
6606: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6607: case F5_720_512:
6608: dpb->media_type = 0xf9;
6609: break;
6610: case FixedMedia: // hard disk
6611: case RemovableMedia:
6612: case Unknown:
6613: dpb->media_type = 0xf8;
6614: break;
6615: default:
6616: dpb->media_type = 0xf0;
6617: break;
6618: }
6619: }
1.1.1.41 root 6620: dpb->next_dpb_ofs = (drive_num == 25) ? 0xffff : *ofs + sizeof(dpb_t);
6621: dpb->next_dpb_seg = (drive_num == 25) ? 0xffff : *seg;
1.1.1.42 root 6622: dpb->info_sector = 0xffff;
6623: dpb->backup_boot_sector = 0xffff;
6624: dpb->free_clusters = 0xffff;
6625: dpb->free_search_cluster = 0xffffffff;
6626:
6627: return(drive_param->valid);
1.1 root 6628: }
6629:
6630: // pc bios
6631:
1.1.1.35 root 6632: #ifdef USE_SERVICE_THREAD
6633: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress)
6634: {
6635: #if defined(HAS_I386)
6636: if(m_SF != 0) {
6637: m_SF = 0;
1.1.1.49 root 6638: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4
1.1.1.35 root 6639: } else {
6640: m_SF = 1;
1.1.1.49 root 6641: mem[DUMMY_TOP + 0x15] = 0x78; // js -4
1.1.1.35 root 6642: }
6643: #else
6644: if(m_SignVal < 0) {
6645: m_SignVal = 0;
1.1.1.49 root 6646: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4
1.1.1.35 root 6647: } else {
6648: m_SignVal = -1;
1.1.1.49 root 6649: mem[DUMMY_TOP + 0x15] = 0x78; // js -4
1.1.1.35 root 6650: }
6651: #endif
1.1.1.49 root 6652: i386_call_far(DUMMY_TOP >> 4, 0x0013);
1.1.1.35 root 6653: in_service = true;
6654: service_exit = false;
6655: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL));
6656: }
6657:
6658: void finish_service_loop()
6659: {
6660: if(in_service && service_exit) {
6661: #if defined(HAS_I386)
6662: if(m_SF != 0) {
6663: m_SF = 0;
6664: } else {
6665: m_SF = 1;
6666: }
6667: #else
6668: if(m_SignVal < 0) {
6669: m_SignVal = 0;
6670: } else {
6671: m_SignVal = -1;
6672: }
6673: #endif
6674: in_service = false;
6675: }
6676: }
6677: #endif
6678:
1.1.1.19 root 6679: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
6680: {
6681: static unsigned __int64 start_msec_since_midnight = 0;
6682: static unsigned __int64 start_msec_since_hostboot = 0;
6683:
6684: if(start_msec_since_midnight == 0) {
6685: SYSTEMTIME time;
6686: GetLocalTime(&time);
6687: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
6688: start_msec_since_hostboot = cur_msec;
6689: }
6690: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
6691: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
6692: return (UINT32)tick;
6693: }
6694:
6695: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
6696: {
6697: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
6698: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
6699:
6700: if(prev_tick > next_tick) {
6701: mem[0x470] = 1;
6702: }
6703: *(UINT32 *)(mem + 0x46c) = next_tick;
6704: }
6705:
1.1.1.14 root 6706: inline void pcbios_irq0()
6707: {
6708: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 6709: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 6710: }
6711:
1.1.1.16 root 6712: int pcbios_get_text_vram_address(int page)
1.1 root 6713: {
6714: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6715: return TEXT_VRAM_TOP;
1.1 root 6716: } else {
1.1.1.14 root 6717: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 6718: }
6719: }
6720:
1.1.1.16 root 6721: int pcbios_get_shadow_buffer_address(int page)
1.1 root 6722: {
1.1.1.14 root 6723: if(!int_10h_feh_called) {
1.1.1.16 root 6724: return pcbios_get_text_vram_address(page);
1.1.1.14 root 6725: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6726: return SHADOW_BUF_TOP;
6727: } else {
1.1.1.14 root 6728: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 6729: }
6730: }
6731:
1.1.1.16 root 6732: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 6733: {
1.1.1.16 root 6734: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 6735: }
6736:
1.1.1.16 root 6737: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 6738: {
1.1.1.14 root 6739: // clear the existing screen, not just the new one
6740: int clr_height = max(height, scr_height);
6741:
1.1.1.16 root 6742: if(scr_width != width || scr_height != height) {
6743: change_console_size(width, height);
1.1.1.14 root 6744: }
6745: mem[0x462] = 0;
6746: *(UINT16 *)(mem + 0x44e) = 0;
6747:
1.1.1.16 root 6748: text_vram_top_address = pcbios_get_text_vram_address(0);
6749: text_vram_end_address = text_vram_top_address + width * height * 2;
6750: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
6751: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1.1.51 root 6752: cursor_position_address = 0x450 + mem[0x462] * 2;
1.1 root 6753:
1.1.1.23 root 6754: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 6755: if(clr_screen) {
1.1.1.14 root 6756: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
6757: mem[ofs++] = 0x20;
6758: mem[ofs++] = 0x07;
6759: }
6760:
1.1.1.35 root 6761: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6762: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6763: #endif
1.1.1.14 root 6764: for(int y = 0; y < clr_height; y++) {
6765: for(int x = 0; x < scr_width; x++) {
6766: SCR_BUF(y,x).Char.AsciiChar = ' ';
6767: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 6768: }
6769: }
6770: SMALL_RECT rect;
1.1.1.14 root 6771: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
6772: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6773: vram_length_char = vram_last_length_char = 0;
6774: vram_length_attr = vram_last_length_attr = 0;
1.1.1.35 root 6775: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6776: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6777: #endif
1.1 root 6778: }
1.1.1.14 root 6779: COORD co;
6780: co.X = 0;
6781: co.Y = scr_top;
6782: SetConsoleCursorPosition(hStdout, co);
6783: cursor_moved = true;
6784: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 6785: }
6786:
1.1.1.36 root 6787: void pcbios_update_cursor_position()
6788: {
6789: CONSOLE_SCREEN_BUFFER_INFO csbi;
6790: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
6791: if(!restore_console_on_exit) {
6792: scr_top = csbi.srWindow.Top;
6793: }
6794: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
6795: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
6796: }
6797:
1.1.1.16 root 6798: inline void pcbios_int_10h_00h()
6799: {
6800: switch(REG8(AL) & 0x7f) {
6801: case 0x70: // v-text mode
6802: case 0x71: // extended cga v-text mode
6803: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
6804: break;
6805: default:
6806: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
6807: break;
6808: }
6809: if(REG8(AL) & 0x80) {
6810: mem[0x487] |= 0x80;
6811: } else {
6812: mem[0x487] &= ~0x80;
6813: }
6814: mem[0x449] = REG8(AL) & 0x7f;
6815: }
6816:
1.1 root 6817: inline void pcbios_int_10h_01h()
6818: {
1.1.1.13 root 6819: mem[0x460] = REG8(CL);
6820: mem[0x461] = REG8(CH);
1.1.1.14 root 6821:
1.1.1.23 root 6822: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6823: CONSOLE_CURSOR_INFO ci;
6824: GetConsoleCursorInfo(hStdout, &ci);
6825: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
6826: // if(ci.bVisible) {
6827: int lines = max(8, REG8(CL) + 1);
6828: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
6829: // }
6830: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 6831: }
6832:
6833: inline void pcbios_int_10h_02h()
6834: {
1.1.1.14 root 6835: // continuously setting the cursor effectively stops it blinking
6836: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 6837: COORD co;
6838: co.X = REG8(DL);
1.1.1.14 root 6839: co.Y = REG8(DH) + scr_top;
6840:
6841: // some programs hide the cursor by moving it off screen
6842: static bool hidden = false;
1.1.1.23 root 6843: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6844: CONSOLE_CURSOR_INFO ci;
6845: GetConsoleCursorInfo(hStdout, &ci);
6846:
6847: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
6848: if(ci.bVisible) {
6849: ci.bVisible = FALSE;
6850: // SetConsoleCursorInfo(hStdout, &ci);
6851: hidden = true;
6852: }
6853: } else if(hidden) {
6854: if(!ci.bVisible) {
6855: ci.bVisible = TRUE;
6856: // SetConsoleCursorInfo(hStdout, &ci);
6857: }
6858: hidden = false;
6859: }
1.1 root 6860: }
1.1.1.14 root 6861: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
6862: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 6863: }
6864:
6865: inline void pcbios_int_10h_03h()
6866: {
1.1.1.14 root 6867: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6868: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6869: REG8(CL) = mem[0x460];
6870: REG8(CH) = mem[0x461];
6871: }
6872:
6873: inline void pcbios_int_10h_05h()
6874: {
1.1.1.14 root 6875: if(REG8(AL) >= vram_pages) {
6876: return;
6877: }
6878: if(mem[0x462] != REG8(AL)) {
6879: vram_flush();
6880:
1.1.1.23 root 6881: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6882: SMALL_RECT rect;
1.1.1.14 root 6883: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6884: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6885:
1.1.1.16 root 6886: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 6887: for(int x = 0; x < scr_width; x++) {
6888: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6889: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6890: }
6891: }
1.1.1.16 root 6892: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 6893: for(int x = 0; x < scr_width; x++) {
6894: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
6895: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 6896: }
6897: }
1.1.1.14 root 6898: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6899:
6900: COORD co;
1.1.1.14 root 6901: co.X = mem[0x450 + REG8(AL) * 2];
6902: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
6903: if(co.Y < scr_top + scr_height) {
6904: SetConsoleCursorPosition(hStdout, co);
6905: }
1.1 root 6906: }
1.1.1.14 root 6907: mem[0x462] = REG8(AL);
6908: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
6909: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 6910: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 6911: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 6912: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 6913: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1.1.51 root 6914: cursor_position_address = 0x450 + mem[0x462] * 2;
1.1 root 6915: }
6916:
6917: inline void pcbios_int_10h_06h()
6918: {
1.1.1.14 root 6919: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6920: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6921: return;
6922: }
6923: vram_flush();
6924:
1.1.1.23 root 6925: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6926: SMALL_RECT rect;
1.1.1.14 root 6927: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6928: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6929:
6930: int right = min(REG8(DL), scr_width - 1);
6931: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6932:
6933: if(REG8(AL) == 0) {
1.1.1.14 root 6934: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6935: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6936: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6937: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6938: }
6939: }
6940: } else {
1.1.1.14 root 6941: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 6942: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6943: if(y2 <= bottom) {
6944: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6945: } else {
1.1.1.14 root 6946: SCR_BUF(y,x).Char.AsciiChar = ' ';
6947: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6948: }
1.1.1.14 root 6949: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6950: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6951: }
6952: }
6953: }
1.1.1.14 root 6954: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6955: }
6956:
6957: inline void pcbios_int_10h_07h()
6958: {
1.1.1.14 root 6959: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6960: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6961: return;
6962: }
6963: vram_flush();
6964:
1.1.1.23 root 6965: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6966: SMALL_RECT rect;
1.1.1.14 root 6967: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6968: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6969:
6970: int right = min(REG8(DL), scr_width - 1);
6971: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6972:
6973: if(REG8(AL) == 0) {
1.1.1.14 root 6974: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6975: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6976: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6977: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6978: }
6979: }
6980: } else {
1.1.1.14 root 6981: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 6982: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6983: if(y2 >= REG8(CH)) {
6984: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6985: } else {
1.1.1.14 root 6986: SCR_BUF(y,x).Char.AsciiChar = ' ';
6987: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6988: }
1.1.1.14 root 6989: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6990: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6991: }
6992: }
6993: }
1.1.1.14 root 6994: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6995: }
6996:
6997: inline void pcbios_int_10h_08h()
6998: {
6999: COORD co;
7000: DWORD num;
7001:
1.1.1.14 root 7002: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7003: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 7004:
7005: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7006: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 7007: co.Y += scr_top;
7008: vram_flush();
1.1 root 7009: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
7010: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
7011: REG8(AL) = scr_char[0];
7012: REG8(AH) = scr_attr[0];
7013: } else {
1.1.1.16 root 7014: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 7015: }
7016: }
7017:
7018: inline void pcbios_int_10h_09h()
7019: {
7020: COORD co;
7021:
1.1.1.14 root 7022: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7023: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7024:
1.1.1.16 root 7025: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
7026: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 7027:
7028: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 7029: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7030: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 7031: #endif
1.1.1.16 root 7032: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 7033: while(dest < end) {
7034: write_text_vram_char(dest - vram, REG8(AL));
7035: mem[dest++] = REG8(AL);
7036: write_text_vram_attr(dest - vram, REG8(BL));
7037: mem[dest++] = REG8(BL);
1.1 root 7038: }
1.1.1.35 root 7039: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7040: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 7041: #endif
1.1 root 7042: } else {
1.1.1.14 root 7043: while(dest < end) {
1.1 root 7044: mem[dest++] = REG8(AL);
7045: mem[dest++] = REG8(BL);
7046: }
7047: }
7048: }
7049:
7050: inline void pcbios_int_10h_0ah()
7051: {
7052: COORD co;
7053:
1.1.1.14 root 7054: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7055: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7056:
1.1.1.16 root 7057: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
7058: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 7059:
7060: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 7061: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7062: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 7063: #endif
1.1.1.16 root 7064: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 7065: while(dest < end) {
7066: write_text_vram_char(dest - vram, REG8(AL));
7067: mem[dest++] = REG8(AL);
7068: dest++;
1.1 root 7069: }
1.1.1.35 root 7070: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7071: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 7072: #endif
1.1 root 7073: } else {
1.1.1.14 root 7074: while(dest < end) {
1.1 root 7075: mem[dest++] = REG8(AL);
7076: dest++;
7077: }
7078: }
7079: }
7080:
1.1.1.40 root 7081: HDC get_console_window_device_context()
7082: {
7083: static HWND hwndFound = 0;
7084:
7085: if(hwndFound == 0) {
7086: // https://support.microsoft.com/en-us/help/124103/how-to-obtain-a-console-window-handle-hwnd
7087: char pszNewWindowTitle[1024];
7088: char pszOldWindowTitle[1024];
7089:
7090: GetConsoleTitle(pszOldWindowTitle, 1024);
7091: wsprintf(pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId());
7092: SetConsoleTitle(pszNewWindowTitle);
7093: Sleep(100);
7094: hwndFound = FindWindow(NULL, pszNewWindowTitle);
7095: SetConsoleTitle(pszOldWindowTitle);
7096: }
7097: return GetDC(hwndFound);
7098: }
7099:
7100: inline void pcbios_int_10h_0ch()
7101: {
7102: HDC hdc = get_console_window_device_context();
7103:
7104: if(hdc != NULL) {
7105: BYTE r = (REG8(AL) & 2) ? 255 : 0;
7106: BYTE g = (REG8(AL) & 4) ? 255 : 0;
7107: BYTE b = (REG8(AL) & 1) ? 255 : 0;
7108:
7109: if(REG8(AL) & 0x80) {
7110: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
7111: if(color != CLR_INVALID) {
7112: r ^= ((DWORD)color & 0x0000ff) ? 255 : 0;
7113: g ^= ((DWORD)color & 0x00ff00) ? 255 : 0;
7114: b ^= ((DWORD)color & 0xff0000) ? 255 : 0;
7115: }
7116: }
7117: SetPixel(hdc, REG16(CX), REG16(DX), RGB(r, g, b));
7118: }
7119: }
7120:
7121: inline void pcbios_int_10h_0dh()
7122: {
7123: HDC hdc = get_console_window_device_context();
7124: BYTE r = 0;
7125: BYTE g = 0;
7126: BYTE b = 0;
7127:
7128: if(hdc != NULL) {
7129: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
7130: if(color != CLR_INVALID) {
7131: r = ((DWORD)color & 0x0000ff) ? 255 : 0;
7132: g = ((DWORD)color & 0x00ff00) ? 255 : 0;
7133: b = ((DWORD)color & 0xff0000) ? 255 : 0;
7134: }
7135: }
7136: REG8(AL) = ((b != 0) ? 1 : 0) | ((r != 0) ? 2 : 0) | ((g != 0) ? 4 : 0);
7137: }
7138:
1.1 root 7139: inline void pcbios_int_10h_0eh()
7140: {
1.1.1.14 root 7141: DWORD num;
7142: COORD co;
7143:
7144: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7145: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7146:
7147: if(REG8(AL) == 7) {
7148: //MessageBeep(-1);
7149: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
7150: if(REG8(AL) == 10) {
7151: vram_flush();
7152: }
1.1.1.23 root 7153: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 7154: cursor_moved = true;
7155: } else {
1.1.1.16 root 7156: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 7157: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 7158: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7159: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 7160: #endif
1.1.1.16 root 7161: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 7162: write_text_vram_char(dest - vram, REG8(AL));
1.1.1.35 root 7163: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7164: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 7165: #endif
1.1.1.14 root 7166:
1.1.1.23 root 7167: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 7168: if(++co.X == scr_width) {
7169: co.X = 0;
7170: if(++co.Y == scr_height) {
7171: vram_flush();
7172: WriteConsole(hStdout, "\n", 1, &num, NULL);
7173: cursor_moved = true;
7174: }
7175: }
7176: if(!cursor_moved) {
7177: co.Y += scr_top;
7178: SetConsoleCursorPosition(hStdout, co);
7179: cursor_moved = true;
7180: }
7181: }
7182: mem[dest] = REG8(AL);
7183: }
1.1 root 7184: }
7185:
7186: inline void pcbios_int_10h_0fh()
7187: {
7188: REG8(AL) = mem[0x449];
7189: REG8(AH) = mem[0x44a];
7190: REG8(BH) = mem[0x462];
7191: }
7192:
1.1.1.14 root 7193: inline void pcbios_int_10h_11h()
7194: {
7195: switch(REG8(AL)) {
1.1.1.16 root 7196: case 0x01:
1.1.1.14 root 7197: case 0x11:
1.1.1.16 root 7198: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 7199: break;
1.1.1.16 root 7200: case 0x02:
1.1.1.14 root 7201: case 0x12:
1.1.1.16 root 7202: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 7203: break;
1.1.1.16 root 7204: case 0x04:
1.1.1.14 root 7205: case 0x14:
1.1.1.16 root 7206: pcbios_set_console_size(80, 25, true);
7207: break;
7208: case 0x18:
7209: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 7210: break;
7211: case 0x30:
7212: SREG(ES) = 0;
7213: i386_load_segment_descriptor(ES);
7214: REG16(BP) = 0;
7215: REG16(CX) = mem[0x485];
7216: REG8(DL) = mem[0x484];
7217: break;
7218: }
7219: }
7220:
7221: inline void pcbios_int_10h_12h()
7222: {
1.1.1.16 root 7223: switch(REG8(BL)) {
7224: case 0x10:
1.1.1.14 root 7225: REG16(BX) = 0x0003;
7226: REG16(CX) = 0x0009;
1.1.1.16 root 7227: break;
1.1.1.14 root 7228: }
7229: }
7230:
1.1 root 7231: inline void pcbios_int_10h_13h()
7232: {
1.1.1.3 root 7233: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 7234: COORD co;
7235: DWORD num;
7236:
7237: co.X = REG8(DL);
1.1.1.14 root 7238: co.Y = REG8(DH) + scr_top;
7239:
7240: vram_flush();
1.1 root 7241:
7242: switch(REG8(AL)) {
7243: case 0x00:
7244: case 0x01:
7245: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7246: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7247: CONSOLE_SCREEN_BUFFER_INFO csbi;
7248: GetConsoleScreenBufferInfo(hStdout, &csbi);
7249: SetConsoleCursorPosition(hStdout, co);
7250:
7251: if(csbi.wAttributes != REG8(BL)) {
7252: SetConsoleTextAttribute(hStdout, REG8(BL));
7253: }
1.1.1.14 root 7254: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
7255:
1.1 root 7256: if(csbi.wAttributes != REG8(BL)) {
7257: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7258: }
7259: if(REG8(AL) == 0x00) {
1.1.1.15 root 7260: if(!restore_console_on_exit) {
7261: GetConsoleScreenBufferInfo(hStdout, &csbi);
7262: scr_top = csbi.srWindow.Top;
7263: }
1.1.1.14 root 7264: co.X = mem[0x450 + REG8(BH) * 2];
7265: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 7266: SetConsoleCursorPosition(hStdout, co);
7267: } else {
7268: cursor_moved = true;
7269: }
7270: } else {
1.1.1.3 root 7271: m_CF = 1;
1.1 root 7272: }
7273: break;
7274: case 0x02:
7275: case 0x03:
7276: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7277: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7278: CONSOLE_SCREEN_BUFFER_INFO csbi;
7279: GetConsoleScreenBufferInfo(hStdout, &csbi);
7280: SetConsoleCursorPosition(hStdout, co);
7281:
7282: WORD wAttributes = csbi.wAttributes;
7283: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
7284: if(wAttributes != mem[ofs + 1]) {
7285: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
7286: wAttributes = mem[ofs + 1];
7287: }
1.1.1.14 root 7288: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 7289: }
7290: if(csbi.wAttributes != wAttributes) {
7291: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7292: }
7293: if(REG8(AL) == 0x02) {
1.1.1.14 root 7294: co.X = mem[0x450 + REG8(BH) * 2];
7295: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 7296: SetConsoleCursorPosition(hStdout, co);
7297: } else {
7298: cursor_moved = true;
7299: }
7300: } else {
1.1.1.3 root 7301: m_CF = 1;
1.1 root 7302: }
7303: break;
7304: case 0x10:
7305: case 0x11:
7306: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7307: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7308: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
7309: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
7310: for(int i = 0; i < num; i++) {
7311: mem[ofs++] = scr_char[i];
7312: mem[ofs++] = scr_attr[i];
1.1.1.45 root 7313: if(REG8(AL) & 0x01) {
1.1 root 7314: mem[ofs++] = 0;
7315: mem[ofs++] = 0;
7316: }
7317: }
7318: } else {
1.1.1.16 root 7319: for(int i = 0, src = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 7320: mem[ofs++] = mem[src++];
7321: mem[ofs++] = mem[src++];
1.1.1.45 root 7322: if(REG8(AL) & 0x01) {
1.1 root 7323: mem[ofs++] = 0;
7324: mem[ofs++] = 0;
7325: }
1.1.1.14 root 7326: if(++co.X == scr_width) {
7327: if(++co.Y == scr_height) {
1.1 root 7328: break;
7329: }
7330: co.X = 0;
7331: }
7332: }
7333: }
7334: break;
1.1.1.45 root 7335: case 0x12: // ???
7336: case 0x13: // ???
1.1 root 7337: case 0x20:
7338: case 0x21:
7339: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7340: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 7341: int len = min(REG16(CX), scr_width * scr_height);
7342: for(int i = 0; i < len; i++) {
1.1 root 7343: scr_char[i] = mem[ofs++];
7344: scr_attr[i] = mem[ofs++];
1.1.1.45 root 7345: if(REG8(AL) & 0x01) {
1.1 root 7346: ofs += 2;
7347: }
7348: }
1.1.1.14 root 7349: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7350: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7351: } else {
1.1.1.16 root 7352: for(int i = 0, dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 7353: mem[dest++] = mem[ofs++];
7354: mem[dest++] = mem[ofs++];
1.1.1.45 root 7355: if(REG8(AL) & 0x01) {
1.1 root 7356: ofs += 2;
7357: }
1.1.1.14 root 7358: if(++co.X == scr_width) {
7359: if(++co.Y == scr_height) {
1.1 root 7360: break;
7361: }
7362: co.X = 0;
7363: }
7364: }
7365: }
7366: break;
7367: default:
1.1.1.22 root 7368: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 7369: m_CF = 1;
1.1 root 7370: break;
7371: }
7372: }
7373:
1.1.1.30 root 7374: inline void pcbios_int_10h_18h()
7375: {
7376: switch(REG8(AL)) {
7377: case 0x00:
7378: case 0x01:
7379: // REG8(AL) = 0x86;
7380: REG8(AL) = 0x00;
7381: break;
7382: default:
7383: 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));
7384: m_CF = 1;
7385: break;
7386: }
7387: }
7388:
1.1.1.14 root 7389: inline void pcbios_int_10h_1ah()
7390: {
7391: switch(REG8(AL)) {
7392: case 0x00:
7393: REG8(AL) = 0x1a;
7394: REG8(BL) = 0x08;
7395: REG8(BH) = 0x00;
7396: break;
7397: default:
1.1.1.22 root 7398: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 7399: m_CF = 1;
7400: break;
7401: }
7402: }
7403:
1.1 root 7404: inline void pcbios_int_10h_1dh()
7405: {
7406: switch(REG8(AL)) {
1.1.1.43 root 7407: case 0x00:
7408: // DOS/V Shift Status Line Control is not supported
7409: m_CF = 1;
7410: break;
1.1 root 7411: case 0x01:
7412: break;
7413: case 0x02:
7414: REG16(BX) = 0;
7415: break;
7416: default:
1.1.1.22 root 7417: 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));
7418: m_CF = 1;
7419: break;
7420: }
7421: }
7422:
7423: inline void pcbios_int_10h_4fh()
7424: {
7425: switch(REG8(AL)) {
7426: case 0x00:
7427: REG8(AH) = 0x02; // not supported
7428: break;
7429: case 0x01:
7430: case 0x02:
7431: case 0x03:
7432: case 0x04:
7433: case 0x05:
7434: case 0x06:
7435: case 0x07:
7436: case 0x08:
7437: case 0x09:
7438: case 0x0a:
7439: case 0x0b:
7440: case 0x0c:
7441: REG8(AH) = 0x01; // failed
7442: break;
7443: default:
7444: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 7445: m_CF = 1;
1.1 root 7446: break;
7447: }
7448: }
7449:
7450: inline void pcbios_int_10h_82h()
7451: {
7452: static UINT8 mode = 0;
7453:
7454: switch(REG8(AL)) {
1.1.1.22 root 7455: case 0x00:
1.1 root 7456: if(REG8(BL) != 0xff) {
7457: mode = REG8(BL);
7458: }
7459: REG8(AL) = mode;
7460: break;
7461: default:
1.1.1.22 root 7462: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 7463: m_CF = 1;
1.1 root 7464: break;
7465: }
7466: }
7467:
1.1.1.22 root 7468: inline void pcbios_int_10h_83h()
7469: {
7470: static UINT8 mode = 0;
7471:
7472: switch(REG8(AL)) {
7473: case 0x00:
7474: REG16(AX) = 0; // offset???
7475: SREG(ES) = (SHADOW_BUF_TOP >> 4);
7476: i386_load_segment_descriptor(ES);
7477: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
7478: break;
7479: default:
7480: 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));
7481: m_CF = 1;
7482: break;
7483: }
7484: }
7485:
7486: inline void pcbios_int_10h_90h()
7487: {
7488: REG8(AL) = mem[0x449];
7489: }
7490:
7491: inline void pcbios_int_10h_91h()
7492: {
7493: REG8(AL) = 0x04; // VGA
7494: }
7495:
7496: inline void pcbios_int_10h_efh()
7497: {
7498: REG16(DX) = 0xffff;
7499: }
7500:
1.1 root 7501: inline void pcbios_int_10h_feh()
7502: {
7503: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 7504: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 7505: i386_load_segment_descriptor(ES);
1.1.1.8 root 7506: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 7507: }
7508: int_10h_feh_called = true;
7509: }
7510:
7511: inline void pcbios_int_10h_ffh()
7512: {
7513: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 7514: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7515: COORD co;
7516: DWORD num;
7517:
1.1.1.14 root 7518: vram_flush();
7519:
7520: co.X = (REG16(DI) >> 1) % scr_width;
7521: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 7522: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
7523: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 7524: int len;
7525: for(len = 0; ofs < end; len++) {
7526: scr_char[len] = mem[ofs++];
7527: scr_attr[len] = mem[ofs++];
7528: }
7529: co.Y += scr_top;
7530: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7531: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7532: }
7533: int_10h_ffh_called = true;
7534: }
7535:
1.1.1.42 root 7536: int pcbios_update_drive_param(int drive_num, int force_update)
7537: {
7538: if(drive_num >= 0 && drive_num < 26) {
7539: drive_param_t *drive_param = &drive_params[drive_num];
7540:
7541: if(force_update || !drive_param->initialized) {
7542: drive_param->valid = 0;
7543: char dev[64];
7544: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7545:
7546: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7547: if(hFile != INVALID_HANDLE_VALUE) {
7548: DWORD dwSize;
7549: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &drive_param->geometry, sizeof(DISK_GEOMETRY), &dwSize, NULL)) {
7550: drive_param->valid = 1;
7551: }
7552: CloseHandle(hFile);
7553: }
7554: drive_param->initialized = 1;
7555: }
7556: return(drive_param->valid);
7557: }
7558: return(0);
7559: }
7560:
7561: inline void pcbios_int_13h_00h()
7562: {
7563: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7564:
7565: if(pcbios_update_drive_param(drive_num, 1)) {
7566: REG8(AH) = 0x00; // successful completion
7567: } else {
7568: if(REG8(DL) & 0x80) {
7569: REG8(AH) = 0x05; // reset failed (hard disk)
7570: } else {
7571: REG8(AH) = 0x80; // timeout (not ready)
7572: }
7573: m_CF = 1;
7574: }
7575: }
7576:
7577: inline void pcbios_int_13h_02h()
7578: {
7579: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7580:
7581: if(REG8(AL) == 0) {
7582: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7583: m_CF = 1;
7584: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7585: REG8(AH) = 0xff; // sense operation failed (hard disk)
7586: m_CF = 1;
7587: } else {
7588: drive_param_t *drive_param = &drive_params[drive_num];
7589: DISK_GEOMETRY *geo = &drive_param->geometry;
7590: char dev[64];
7591: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7592:
7593: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7594: if(hFile == INVALID_HANDLE_VALUE) {
7595: REG8(AH) = 0xff; // sense operation failed (hard disk)
7596: m_CF = 1;
7597: } else {
7598: UINT32 sector_num = REG8(AL);
7599: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7600: UINT32 head = REG8(DH);
7601: UINT32 sector = REG8(CL) & 0x3f;
7602: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7603: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7604: DWORD dwSize;
7605:
7606: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7607: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7608: // m_CF = 1;
7609: // } else
7610: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7611: REG8(AH) = 0x04; // sector not found/read error
7612: m_CF = 1;
7613: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7614: REG8(AH) = 0x04; // sector not found/read error
7615: m_CF = 1;
7616: } else {
7617: REG8(AH) = 0x00; // successful completion
7618: }
7619: CloseHandle(hFile);
7620: }
7621: }
7622: }
7623:
7624: inline void pcbios_int_13h_03h()
7625: {
7626: // this operation may cause serious damage for drives, so support only floppy disk...
7627: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7628:
7629: if(REG8(AL) == 0) {
7630: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7631: m_CF = 1;
7632: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7633: REG8(AH) = 0xff; // sense operation failed (hard disk)
7634: m_CF = 1;
7635: } else if(!drive_params[drive_num].is_fdd()) {
7636: REG8(AH) = 0xff; // sense operation failed (hard disk)
7637: m_CF = 1;
7638: } else {
7639: drive_param_t *drive_param = &drive_params[drive_num];
7640: DISK_GEOMETRY *geo = &drive_param->geometry;
7641: char dev[64];
7642: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7643:
7644: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7645: if(hFile == INVALID_HANDLE_VALUE) {
7646: REG8(AH) = 0xff; // sense operation failed (hard disk)
7647: m_CF = 1;
7648: } else {
7649: UINT32 sector_num = REG8(AL);
7650: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7651: UINT32 head = REG8(DH);
7652: UINT32 sector = REG8(CL) & 0x3f;
7653: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7654: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7655: DWORD dwSize;
7656:
7657: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7658: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7659: // m_CF = 1;
7660: // } else
7661: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7662: REG8(AH) = 0x04; // sector not found/read error
7663: m_CF = 1;
7664: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7665: REG8(AH) = 0x04; // sector not found/read error
7666: m_CF = 1;
7667: } else {
7668: REG8(AH) = 0x00; // successful completion
7669: }
7670: CloseHandle(hFile);
7671: }
7672: }
7673: }
7674:
7675: inline void pcbios_int_13h_04h()
7676: {
7677: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7678:
7679: if(REG8(AL) == 0) {
7680: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7681: m_CF = 1;
7682: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7683: REG8(AH) = 0xff; // sense operation failed (hard disk)
7684: m_CF = 1;
7685: } else {
7686: drive_param_t *drive_param = &drive_params[drive_num];
7687: DISK_GEOMETRY *geo = &drive_param->geometry;
7688: char dev[64];
7689: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7690:
7691: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7692: if(hFile == INVALID_HANDLE_VALUE) {
7693: REG8(AH) = 0xff; // sense operation failed (hard disk)
7694: m_CF = 1;
7695: } else {
7696: UINT32 sector_num = REG8(AL);
7697: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7698: UINT32 head = REG8(DH);
7699: UINT32 sector = REG8(CL) & 0x3f;
7700: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7701: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7702: DWORD dwSize;
7703: UINT8 *tmp_buffer = (UINT8 *)malloc(sector_num * geo->BytesPerSector);
7704:
7705: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7706: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7707: // m_CF = 1;
7708: // } else
7709: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7710: REG8(AH) = 0x04; // sector not found/read error
7711: m_CF = 1;
7712: } else if(ReadFile(hFile, tmp_buffer, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7713: REG8(AH) = 0x04; // sector not found/read error
7714: m_CF = 1;
7715: } else if(memcmp(mem + buffer_addr, tmp_buffer, sector_num * geo->BytesPerSector) != 0) {
7716: REG8(AH) = 0x05; // data did not verify correctly (TI Professional PC)
7717: m_CF = 1;
7718: } else {
7719: REG8(AH) = 0x00; // successful completion
7720: }
7721: free(tmp_buffer);
7722: CloseHandle(hFile);
7723: }
7724: }
7725: }
7726:
7727: inline void pcbios_int_13h_08h()
7728: {
7729: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7730:
7731: if(pcbios_update_drive_param(drive_num, 1)) {
7732: drive_param_t *drive_param = &drive_params[drive_num];
7733: DISK_GEOMETRY *geo = &drive_param->geometry;
7734:
7735: REG16(AX) = 0x0000;
7736: switch(geo->MediaType) {
7737: case F5_360_512:
7738: case F5_320_512:
7739: case F5_320_1024:
7740: case F5_180_512:
7741: case F5_160_512:
7742: REG8(BL) = 0x01; // 320K/360K disk
7743: break;
7744: case F5_1Pt2_512:
7745: case F3_1Pt2_512:
7746: case F3_1Pt23_1024:
7747: case F5_1Pt23_1024:
7748: REG8(BL) = 0x02; // 1.2M disk
7749: break;
7750: case F3_720_512:
7751: case F3_640_512:
7752: case F5_640_512:
7753: case F5_720_512:
7754: REG8(BL) = 0x03; // 720K disk
7755: break;
7756: case F3_1Pt44_512:
7757: REG8(BL) = 0x04; // 1.44M disk
7758: break;
7759: case F3_2Pt88_512:
7760: REG8(BL) = 0x06; // 2.88M disk
7761: break;
7762: case RemovableMedia:
7763: REG8(BL) = 0x10; // ATAPI Removable Media Device
7764: break;
7765: default:
7766: REG8(BL) = 0x00; // unknown
7767: break;
7768: }
7769: if(REG8(DL) & 0x80) {
7770: switch(GetLogicalDrives() & 0x0c) {
7771: case 0x00: REG8(DL) = 0x00; break;
7772: case 0x04:
7773: case 0x08: REG8(DL) = 0x01; break;
7774: case 0x0c: REG8(DL) = 0x02; break;
7775: }
7776: } else {
7777: switch(GetLogicalDrives() & 0x03) {
7778: case 0x00: REG8(DL) = 0x00; break;
7779: case 0x01:
7780: case 0x02: REG8(DL) = 0x01; break;
7781: case 0x03: REG8(DL) = 0x02; break;
7782: }
7783: }
7784: REG8(DH) = drive_param->head_num();
7785: int cyl = (geo->Cylinders.QuadPart > 0x3ff) ? 0x3ff : geo->Cylinders.QuadPart;
7786: int sec = (geo->SectorsPerTrack > 0x3f) ? 0x3f : geo->SectorsPerTrack;
7787: REG8(CH) = cyl & 0xff;
7788: REG8(CL) = (sec & 0x3f) | ((cyl & 0x300) >> 2);
7789: } else {
7790: REG8(AH) = 0x07;
7791: m_CF = 1;
7792: }
7793: }
7794:
7795: inline void pcbios_int_13h_10h()
7796: {
7797: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7798:
7799: if(pcbios_update_drive_param(drive_num, 1)) {
7800: REG8(AH) = 0x00; // successful completion
7801: } else {
7802: if(REG8(DL) & 0x80) {
7803: REG8(AH) = 0xaa; // drive not ready (hard disk)
7804: } else {
7805: REG8(AH) = 0x80; // timeout (not ready)
7806: }
7807: m_CF = 1;
7808: }
7809: }
7810:
7811: inline void pcbios_int_13h_15h()
7812: {
7813: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7814:
7815: if(pcbios_update_drive_param(drive_num, 1)) {
7816: if(REG8(DL) & 0x80) {
7817: REG8(AH) = 0x02; // floppy (or other removable drive) with change-line support
7818: } else {
7819: REG8(AH) = 0x03; // hard disk
7820: }
7821: } else {
7822: REG8(AH) = 0x00; // no such drive
7823: }
7824: }
7825:
1.1.1.43 root 7826: inline void pcbios_int_13h_41h()
7827: {
7828: if(REG16(BX) == 0x55aa) {
7829: // IBM/MS INT 13 Extensions is not installed
7830: REG8(AH) = 0x01;
7831: m_CF = 1;
7832: } else {
7833: 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));
7834: REG8(AH) = 0x01;
7835: m_CF = 1;
7836: }
7837: }
7838:
1.1.1.25 root 7839: inline void pcbios_int_14h_00h()
7840: {
1.1.1.29 root 7841: if(REG16(DX) < 4) {
1.1.1.25 root 7842: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
7843: UINT8 selector = sio_read(REG16(DX), 3);
7844: selector &= ~0x3f;
7845: selector |= REG8(AL) & 0x1f;
7846: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
7847: sio_write(REG16(DX), 3, selector | 0x80);
7848: sio_write(REG16(DX), 0, divisor & 0xff);
7849: sio_write(REG16(DX), 1, divisor >> 8);
7850: sio_write(REG16(DX), 3, selector);
7851: REG8(AH) = sio_read(REG16(DX), 5);
7852: REG8(AL) = sio_read(REG16(DX), 6);
7853: } else {
7854: REG8(AH) = 0x80;
7855: }
7856: }
7857:
7858: inline void pcbios_int_14h_01h()
7859: {
1.1.1.29 root 7860: if(REG16(DX) < 4) {
1.1.1.25 root 7861: UINT8 selector = sio_read(REG16(DX), 3);
7862: sio_write(REG16(DX), 3, selector & ~0x80);
7863: sio_write(REG16(DX), 0, REG8(AL));
7864: sio_write(REG16(DX), 3, selector);
7865: REG8(AH) = sio_read(REG16(DX), 5);
7866: } else {
7867: REG8(AH) = 0x80;
7868: }
7869: }
7870:
7871: inline void pcbios_int_14h_02h()
7872: {
1.1.1.29 root 7873: if(REG16(DX) < 4) {
1.1.1.25 root 7874: UINT8 selector = sio_read(REG16(DX), 3);
7875: sio_write(REG16(DX), 3, selector & ~0x80);
7876: REG8(AL) = sio_read(REG16(DX), 0);
7877: sio_write(REG16(DX), 3, selector);
7878: REG8(AH) = sio_read(REG16(DX), 5);
7879: } else {
7880: REG8(AH) = 0x80;
7881: }
7882: }
7883:
7884: inline void pcbios_int_14h_03h()
7885: {
1.1.1.29 root 7886: if(REG16(DX) < 4) {
1.1.1.25 root 7887: REG8(AH) = sio_read(REG16(DX), 5);
7888: REG8(AL) = sio_read(REG16(DX), 6);
7889: } else {
7890: REG8(AH) = 0x80;
7891: }
7892: }
7893:
7894: inline void pcbios_int_14h_04h()
7895: {
1.1.1.29 root 7896: if(REG16(DX) < 4) {
1.1.1.25 root 7897: UINT8 selector = sio_read(REG16(DX), 3);
7898: if(REG8(CH) <= 0x03) {
7899: selector = (selector & ~0x03) | REG8(CH);
7900: }
7901: if(REG8(BL) == 0x00) {
7902: selector &= ~0x04;
7903: } else if(REG8(BL) == 0x01) {
7904: selector |= 0x04;
7905: }
7906: if(REG8(BH) == 0x00) {
7907: selector = (selector & ~0x38) | 0x00;
7908: } else if(REG8(BH) == 0x01) {
7909: selector = (selector & ~0x38) | 0x08;
7910: } else if(REG8(BH) == 0x02) {
7911: selector = (selector & ~0x38) | 0x18;
7912: } else if(REG8(BH) == 0x03) {
7913: selector = (selector & ~0x38) | 0x28;
7914: } else if(REG8(BH) == 0x04) {
7915: selector = (selector & ~0x38) | 0x38;
7916: }
7917: if(REG8(AL) == 0x00) {
7918: selector |= 0x40;
7919: } else if(REG8(AL) == 0x01) {
7920: selector &= ~0x40;
7921: }
7922: if(REG8(CL) <= 0x0b) {
7923: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
7924: UINT16 divisor = 115200 / rate[REG8(CL)];
7925: sio_write(REG16(DX), 3, selector | 0x80);
7926: sio_write(REG16(DX), 0, divisor & 0xff);
7927: sio_write(REG16(DX), 1, divisor >> 8);
7928: }
7929: sio_write(REG16(DX), 3, selector);
7930: REG8(AH) = sio_read(REG16(DX), 5);
7931: REG8(AL) = sio_read(REG16(DX), 6);
7932: } else {
7933: REG8(AH) = 0x80;
7934: }
7935: }
7936:
7937: inline void pcbios_int_14h_05h()
7938: {
1.1.1.29 root 7939: if(REG16(DX) < 4) {
1.1.1.25 root 7940: if(REG8(AL) == 0x00) {
7941: REG8(BL) = sio_read(REG16(DX), 4);
7942: REG8(AH) = sio_read(REG16(DX), 5);
7943: REG8(AL) = sio_read(REG16(DX), 6);
7944: } else if(REG8(AL) == 0x01) {
7945: sio_write(REG16(DX), 4, REG8(BL));
7946: REG8(AH) = sio_read(REG16(DX), 5);
7947: REG8(AL) = sio_read(REG16(DX), 6);
7948: } else {
7949: 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));
7950: }
7951: } else {
7952: REG8(AH) = 0x80;
7953: }
7954: }
7955:
1.1.1.14 root 7956: inline void pcbios_int_15h_10h()
7957: {
1.1.1.22 root 7958: switch(REG8(AL)) {
7959: case 0x00:
1.1.1.14 root 7960: Sleep(10);
1.1.1.35 root 7961: REQUEST_HARDWRE_UPDATE();
1.1.1.22 root 7962: break;
7963: default:
7964: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 7965: REG8(AH) = 0x86;
7966: m_CF = 1;
7967: }
7968: }
7969:
1.1 root 7970: inline void pcbios_int_15h_23h()
7971: {
7972: switch(REG8(AL)) {
1.1.1.22 root 7973: case 0x00:
1.1.1.8 root 7974: REG8(CL) = cmos_read(0x2d);
7975: REG8(CH) = cmos_read(0x2e);
1.1 root 7976: break;
1.1.1.22 root 7977: case 0x01:
1.1.1.8 root 7978: cmos_write(0x2d, REG8(CL));
7979: cmos_write(0x2e, REG8(CH));
1.1 root 7980: break;
7981: default:
1.1.1.22 root 7982: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 7983: REG8(AH) = 0x86;
1.1.1.3 root 7984: m_CF = 1;
1.1 root 7985: break;
7986: }
7987: }
7988:
7989: inline void pcbios_int_15h_24h()
7990: {
7991: switch(REG8(AL)) {
1.1.1.22 root 7992: case 0x00:
1.1.1.3 root 7993: i386_set_a20_line(0);
1.1 root 7994: REG8(AH) = 0;
7995: break;
1.1.1.22 root 7996: case 0x01:
1.1.1.3 root 7997: i386_set_a20_line(1);
1.1 root 7998: REG8(AH) = 0;
7999: break;
1.1.1.22 root 8000: case 0x02:
1.1 root 8001: REG8(AH) = 0;
1.1.1.3 root 8002: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 8003: REG16(CX) = 0;
8004: break;
1.1.1.22 root 8005: case 0x03:
1.1 root 8006: REG16(AX) = 0;
8007: REG16(BX) = 0;
8008: break;
1.1.1.22 root 8009: default:
8010: 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));
8011: REG8(AH) = 0x86;
8012: m_CF = 1;
8013: break;
1.1 root 8014: }
8015: }
8016:
8017: inline void pcbios_int_15h_49h()
8018: {
1.1.1.27 root 8019: REG8(AH) = 0x00;
8020: REG8(BL) = 0x00; // DOS/V
1.1 root 8021: }
8022:
1.1.1.22 root 8023: inline void pcbios_int_15h_50h()
8024: {
8025: switch(REG8(AL)) {
8026: case 0x00:
8027: case 0x01:
8028: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
8029: REG8(AH) = 0x01; // invalid font type in bh
8030: m_CF = 1;
1.1.1.27 root 8031: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 8032: REG8(AH) = 0x02; // bl not zero
8033: m_CF = 1;
8034: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
8035: REG8(AH) = 0x04; // invalid code page
8036: m_CF = 1;
1.1.1.27 root 8037: } else if(REG8(AL) == 0x01) {
8038: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 8039: m_CF = 1;
1.1.1.27 root 8040: } else {
1.1.1.49 root 8041: // dummy font read routine is at fffc:000d
8042: SREG(ES) = DUMMY_TOP >> 4;
1.1.1.27 root 8043: i386_load_segment_descriptor(ES);
1.1.1.32 root 8044: REG16(BX) = 0x000d;
1.1.1.27 root 8045: REG8(AH) = 0x00; // success
1.1.1.22 root 8046: }
8047: break;
8048: default:
8049: 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));
8050: REG8(AH) = 0x86;
8051: m_CF = 1;
8052: break;
8053: }
8054: }
8055:
1.1.1.30 root 8056: inline void pcbios_int_15h_53h()
8057: {
8058: switch(REG8(AL)) {
8059: case 0x00:
8060: // APM is not installed
8061: REG8(AH) = 0x86;
8062: m_CF = 1;
8063: break;
8064: default:
8065: 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));
8066: REG8(AH) = 0x86;
8067: m_CF = 1;
8068: break;
8069: }
8070: }
8071:
1.1.1.43 root 8072: inline void pcbios_int_15h_84h()
8073: {
8074: // joystick support (from DOSBox)
8075: switch(REG16(DX)) {
8076: case 0x00:
8077: REG16(AX) = 0x00f0;
8078: REG16(DX) = 0x0201;
8079: m_CF = 1;
8080: break;
8081: case 0x01:
8082: REG16(AX) = REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
8083: m_CF = 1;
8084: break;
8085: default:
8086: 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));
8087: REG8(AH) = 0x86;
8088: m_CF = 1;
8089: break;
8090: }
8091: }
1.1.1.35 root 8092:
8093: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID)
1.1 root 8094: {
8095: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 8096: UINT32 msec = usec / 1000;
8097:
1.1.1.35 root 8098: while(msec && !m_halted) {
1.1.1.14 root 8099: UINT32 tmp = min(msec, 100);
8100: if(msec - tmp < 10) {
8101: tmp = msec;
8102: }
8103: Sleep(tmp);
8104: msec -= tmp;
8105: }
1.1.1.35 root 8106:
8107: #ifdef USE_SERVICE_THREAD
8108: service_exit = true;
8109: #endif
8110: return(0);
8111: }
8112:
8113: inline void pcbios_int_15h_86h()
8114: {
8115: if(!(REG16(CX) == 0 && REG16(DX) == 0)) {
8116: #ifdef USE_SERVICE_THREAD
1.1.1.51 root 8117: if(!in_service && !in_service_29h) {
8118: start_service_loop(pcbios_int_15h_86h_thread);
8119: } else {
8120: #endif
8121: pcbios_int_15h_86h_thread(NULL);
8122: REQUEST_HARDWRE_UPDATE();
8123: #ifdef USE_SERVICE_THREAD
8124: }
1.1.1.35 root 8125: #endif
8126: }
1.1 root 8127: }
8128:
8129: inline void pcbios_int_15h_87h()
8130: {
8131: // copy extended memory (from DOSBox)
8132: int len = REG16(CX) * 2;
1.1.1.3 root 8133: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 8134: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
8135: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
8136: memcpy(mem + dst, mem + src, len);
8137: REG16(AX) = 0x00;
8138: }
8139:
8140: inline void pcbios_int_15h_88h()
8141: {
1.1.1.17 root 8142: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 8143: }
8144:
8145: inline void pcbios_int_15h_89h()
8146: {
1.1.1.21 root 8147: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 8148: // switch to protected mode (from DOSBox)
8149: write_io_byte(0x20, 0x10);
8150: write_io_byte(0x21, REG8(BH));
8151: write_io_byte(0x21, 0x00);
8152: write_io_byte(0xa0, 0x10);
8153: write_io_byte(0xa1, REG8(BL));
8154: write_io_byte(0xa1, 0x00);
1.1.1.3 root 8155: i386_set_a20_line(1);
8156: int ofs = SREG_BASE(ES) + REG16(SI);
8157: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
8158: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
8159: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
8160: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
8161: #if defined(HAS_I386)
8162: m_cr[0] |= 1;
8163: #else
8164: m_msw |= 1;
8165: #endif
8166: SREG(DS) = 0x18;
8167: SREG(ES) = 0x20;
8168: SREG(SS) = 0x28;
8169: i386_load_segment_descriptor(DS);
8170: i386_load_segment_descriptor(ES);
8171: i386_load_segment_descriptor(SS);
1.1.1.21 root 8172: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 8173: REG16(SP) += 6;
1.1.1.3 root 8174: #if defined(HAS_I386)
1.1.1.21 root 8175: UINT32 flags = get_flags();
8176: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
8177: set_flags(flags);
1.1.1.3 root 8178: #else
1.1.1.21 root 8179: UINT32 flags = CompressFlags();
8180: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
8181: ExpandFlags(flags);
1.1.1.3 root 8182: #endif
1.1 root 8183: REG16(AX) = 0x00;
1.1.1.21 root 8184: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 8185: #else
1.1.1.21 root 8186: // i86/i186/v30: protected mode is not supported
1.1 root 8187: REG8(AH) = 0x86;
1.1.1.3 root 8188: m_CF = 1;
1.1 root 8189: #endif
8190: }
8191:
1.1.1.21 root 8192: inline void pcbios_int_15h_8ah()
8193: {
8194: UINT32 size = MAX_MEM - 0x100000;
8195: REG16(AX) = size & 0xffff;
8196: REG16(DX) = size >> 16;
8197: }
8198:
1.1.1.3 root 8199: #if defined(HAS_I386)
1.1 root 8200: inline void pcbios_int_15h_c9h()
8201: {
8202: REG8(AH) = 0x00;
8203: REG8(CH) = cpu_type;
8204: REG8(CL) = cpu_step;
8205: }
1.1.1.3 root 8206: #endif
1.1 root 8207:
8208: inline void pcbios_int_15h_cah()
8209: {
8210: switch(REG8(AL)) {
1.1.1.22 root 8211: case 0x00:
1.1 root 8212: if(REG8(BL) > 0x3f) {
8213: REG8(AH) = 0x03;
1.1.1.3 root 8214: m_CF = 1;
1.1 root 8215: } else if(REG8(BL) < 0x0e) {
8216: REG8(AH) = 0x04;
1.1.1.3 root 8217: m_CF = 1;
1.1 root 8218: } else {
1.1.1.8 root 8219: REG8(CL) = cmos_read(REG8(BL));
1.1 root 8220: }
8221: break;
1.1.1.22 root 8222: case 0x01:
1.1 root 8223: if(REG8(BL) > 0x3f) {
8224: REG8(AH) = 0x03;
1.1.1.3 root 8225: m_CF = 1;
1.1 root 8226: } else if(REG8(BL) < 0x0e) {
8227: REG8(AH) = 0x04;
1.1.1.3 root 8228: m_CF = 1;
1.1 root 8229: } else {
1.1.1.8 root 8230: cmos_write(REG8(BL), REG8(CL));
1.1 root 8231: }
8232: break;
8233: default:
1.1.1.22 root 8234: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8235: REG8(AH) = 0x86;
1.1.1.3 root 8236: m_CF = 1;
1.1 root 8237: break;
8238: }
8239: }
8240:
1.1.1.22 root 8241: inline void pcbios_int_15h_e8h()
1.1.1.17 root 8242: {
1.1.1.22 root 8243: switch(REG8(AL)) {
8244: #if defined(HAS_I386)
8245: case 0x01:
8246: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
8247: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
8248: break;
1.1.1.17 root 8249: #endif
1.1.1.22 root 8250: default:
8251: 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));
8252: REG8(AH) = 0x86;
8253: m_CF = 1;
8254: break;
8255: }
8256: }
1.1.1.17 root 8257:
1.1.1.51 root 8258: void pcbios_clear_key_buffer()
8259: {
8260: key_buf_char->clear();
8261: key_buf_scan->clear();
8262:
8263: // update key buffer
8264: *(UINT16 *)(mem + 0x41a) = *(UINT16 *)(mem + 0x41c); // head = tail
8265: }
8266:
8267: void pcbios_set_key_buffer(int key_char, int key_scan)
8268: {
8269: key_buf_char->write(key_char);
8270: key_buf_scan->write(key_scan);
8271:
8272: // update key buffer
8273: UINT16 head = *(UINT16 *)(mem + 0x41a);
8274: UINT16 tail = *(UINT16 *)(mem + 0x41c);
8275: UINT16 next = tail + 2;
8276: if(next >= *(UINT16 *)(mem + 0x482)) {
8277: next = *(UINT16 *)(mem + 0x480);
8278: }
8279: if(next != head) {
8280: *(UINT16 *)(mem + 0x41c) = next;
8281: mem[0x400 + (tail++)] = key_char;
8282: mem[0x400 + (tail++)] = key_scan;
8283: }
8284: }
8285:
8286: bool pcbios_get_key_buffer(int *key_char, int *key_scan)
8287: {
8288: if(key_buf_char->empty()) {
8289: *key_char = 0x00;
8290: *key_scan = 0x00;
8291: return(false);
8292: }
8293: *key_char = key_buf_char->read();
8294: *key_scan = key_buf_scan->read();
8295:
8296: // update key buffer
8297: UINT16 head = *(UINT16 *)(mem + 0x41a);
8298: UINT16 tail = *(UINT16 *)(mem + 0x41c);
8299: UINT16 next = head + 2;
8300: if(next >= *(UINT16 *)(mem + 0x482)) {
8301: next = *(UINT16 *)(mem + 0x480);
8302: }
8303: if(head != tail) {
8304: *(UINT16 *)(mem + 0x41a) = next;
8305: // *key_char = mem[0x400 + (head++)];
8306: // *key_scan = mem[0x400 + (head++)];
8307: }
8308: return(true);
8309: }
8310:
1.1.1.33 root 8311: void pcbios_update_key_code(bool wait)
1.1 root 8312: {
1.1.1.32 root 8313: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8314: #ifdef USE_SERVICE_THREAD
8315: EnterCriticalSection(&key_buf_crit_sect);
8316: #endif
8317: bool empty = key_buf_char->empty();
8318: #ifdef USE_SERVICE_THREAD
8319: LeaveCriticalSection(&key_buf_crit_sect);
8320: #endif
8321: if(empty) {
1.1.1.32 root 8322: if(!update_key_buffer()) {
1.1.1.33 root 8323: if(wait) {
1.1.1.32 root 8324: Sleep(10);
8325: } else {
8326: maybe_idle();
8327: }
1.1.1.14 root 8328: }
8329: }
1.1.1.34 root 8330: }
8331: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8332: #ifdef USE_SERVICE_THREAD
8333: EnterCriticalSection(&key_buf_crit_sect);
8334: #endif
1.1.1.51 root 8335: int key_char, key_scan;
8336: if(pcbios_get_key_buffer(&key_char, &key_scan)) {
1.1.1.41 root 8337: key_code = key_char << 0;
8338: key_code |= key_scan << 8;
1.1.1.35 root 8339: key_recv = 0x0000ffff;
1.1.1.51 root 8340: }
8341: if(pcbios_get_key_buffer(&key_char, &key_scan)) {
1.1.1.41 root 8342: key_code |= key_char << 16;
8343: key_code |= key_scan << 24;
1.1.1.33 root 8344: key_recv |= 0xffff0000;
1.1.1.32 root 8345: }
1.1.1.35 root 8346: #ifdef USE_SERVICE_THREAD
8347: LeaveCriticalSection(&key_buf_crit_sect);
8348: #endif
1.1 root 8349: }
8350: }
8351:
1.1.1.35 root 8352: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID)
1.1 root 8353: {
1.1.1.33 root 8354: while(key_recv == 0 && !m_halted) {
8355: pcbios_update_key_code(true);
1.1 root 8356: }
1.1.1.33 root 8357: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
8358: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
8359: if(REG8(AH) == 0x10) {
8360: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
8361: } else {
8362: key_code = ((key_code >> 16) & 0xff00);
8363: }
8364: key_recv >>= 16;
1.1 root 8365: }
8366: }
8367: REG16(AX) = key_code & 0xffff;
8368: key_code >>= 16;
1.1.1.33 root 8369: key_recv >>= 16;
1.1.1.35 root 8370:
8371: #ifdef USE_SERVICE_THREAD
8372: service_exit = true;
8373: #endif
8374: return(0);
8375: }
8376:
8377: inline void pcbios_int_16h_00h()
8378: {
8379: #ifdef USE_SERVICE_THREAD
1.1.1.51 root 8380: if(!in_service && !in_service_29h) {
8381: start_service_loop(pcbios_int_16h_00h_thread);
8382: } else {
8383: #endif
8384: pcbios_int_16h_00h_thread(NULL);
8385: REQUEST_HARDWRE_UPDATE();
8386: #ifdef USE_SERVICE_THREAD
8387: }
1.1.1.35 root 8388: #endif
1.1 root 8389: }
8390:
8391: inline void pcbios_int_16h_01h()
8392: {
1.1.1.33 root 8393: if(key_recv == 0) {
8394: pcbios_update_key_code(false);
1.1.1.5 root 8395: }
1.1.1.33 root 8396: if(key_recv != 0) {
8397: UINT32 key_code_tmp = key_code;
8398: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
8399: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
8400: if(REG8(AH) == 0x11) {
8401: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
8402: } else {
8403: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
8404: }
8405: }
1.1 root 8406: }
1.1.1.5 root 8407: REG16(AX) = key_code_tmp & 0xffff;
1.1.1.3 root 8408: #if defined(HAS_I386)
1.1.1.33 root 8409: m_ZF = 0;
8410: #else
8411: m_ZeroVal = 1;
8412: #endif
8413: } else {
8414: #if defined(HAS_I386)
8415: m_ZF = 1;
1.1.1.3 root 8416: #else
1.1.1.33 root 8417: m_ZeroVal = 0;
1.1.1.3 root 8418: #endif
1.1.1.33 root 8419: }
1.1 root 8420: }
8421:
8422: inline void pcbios_int_16h_02h()
8423: {
8424: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
8425: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
8426: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
8427: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
8428: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
8429: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
8430: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
8431: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
8432: }
8433:
8434: inline void pcbios_int_16h_03h()
8435: {
8436: static UINT16 status = 0;
8437:
8438: switch(REG8(AL)) {
8439: case 0x05:
8440: status = REG16(BX);
8441: break;
8442: case 0x06:
8443: REG16(BX) = status;
8444: break;
8445: default:
1.1.1.3 root 8446: m_CF = 1;
1.1 root 8447: break;
8448: }
8449: }
8450:
8451: inline void pcbios_int_16h_05h()
8452: {
1.1.1.32 root 8453: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8454: #ifdef USE_SERVICE_THREAD
8455: EnterCriticalSection(&key_buf_crit_sect);
8456: #endif
1.1.1.51 root 8457: pcbios_set_key_buffer(REG8(CL), REG8(CH));
1.1.1.35 root 8458: #ifdef USE_SERVICE_THREAD
8459: LeaveCriticalSection(&key_buf_crit_sect);
8460: #endif
1.1.1.32 root 8461: }
1.1 root 8462: REG8(AL) = 0x00;
8463: }
8464:
8465: inline void pcbios_int_16h_12h()
8466: {
8467: pcbios_int_16h_02h();
8468:
8469: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
8470: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
8471: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
8472: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
8473: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
8474: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
8475: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
8476: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
8477: }
8478:
8479: inline void pcbios_int_16h_13h()
8480: {
8481: static UINT16 status = 0;
8482:
8483: switch(REG8(AL)) {
8484: case 0x00:
8485: status = REG16(DX);
8486: break;
8487: case 0x01:
8488: REG16(DX) = status;
8489: break;
8490: default:
1.1.1.22 root 8491: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 8492: m_CF = 1;
1.1 root 8493: break;
8494: }
8495: }
8496:
8497: inline void pcbios_int_16h_14h()
8498: {
8499: static UINT8 status = 0;
8500:
8501: switch(REG8(AL)) {
8502: case 0x00:
8503: case 0x01:
8504: status = REG8(AL);
8505: break;
8506: case 0x02:
8507: REG8(AL) = status;
8508: break;
8509: default:
1.1.1.22 root 8510: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 8511: m_CF = 1;
1.1 root 8512: break;
8513: }
8514: }
8515:
1.1.1.24 root 8516: inline void pcbios_int_16h_55h()
8517: {
8518: switch(REG8(AL)) {
8519: case 0x00:
8520: // keyboard tsr is not present
8521: break;
8522: case 0xfe:
8523: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
8524: break;
8525: case 0xff:
8526: break;
8527: default:
8528: 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));
8529: m_CF = 1;
8530: break;
8531: }
8532: }
8533:
1.1.1.30 root 8534: inline void pcbios_int_16h_6fh()
8535: {
8536: switch(REG8(AL)) {
8537: case 0x00:
8538: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
8539: break;
8540: default:
8541: 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));
8542: m_CF = 1;
8543: break;
8544: }
8545: }
8546:
1.1.1.37 root 8547: UINT16 pcbios_printer_jis2sjis(UINT16 jis)
8548: {
8549: UINT8 hi = jis >> 8;
8550: UINT8 lo = jis & 0xff;
8551:
8552: lo = (hi & 0x01) ? lo - 0x1f : lo + 0x7d;
8553: hi = (hi - 0x21) / 2 + 0x81;
8554: hi = (hi >= 0xa0) ? hi + 0x40 : hi;
8555: lo = (lo >= 0x7f) ? lo + 0x01 : lo;
8556:
8557: return((hi << 8) + lo);
8558: }
8559:
8560: UINT16 pcbios_printer_sjis2jis(UINT16 sjis)
8561: {
8562: UINT8 hi = sjis >> 8;
8563: UINT8 lo = sjis & 0xff;
8564:
8565: if(hi == 0x80 || (hi >= 0xeb && hi <= 0xef) || (hi >= 0xf4 && hi <= 0xff)) {
8566: return(0x2121);
8567: }
8568: if((lo >= 0x00 && lo <= 0x3f) || lo == 0x7f || (lo >= 0xfd && lo <= 0xff)) {
8569: return(0x2121);
8570: }
8571: if(hi >= 0xf0 && hi <= 0xf3) {
8572: // gaiji
8573: if(lo >= 0x40 && lo <= 0x7e) {
8574: return(0x7721 + lo - 0x40 + (hi - 0xf0) * 0x200);
8575: }
8576: if(lo >= 0x80 && lo <= 0x9e) {
8577: return(0x7760 + lo - 0x80 + (hi - 0xf0) * 0x200);
8578: }
8579: if(lo >= 0x9f && lo <= 0xfc) {
8580: return(0x7821 + lo - 0x9f + (hi - 0xf0) * 0x200);
8581: }
8582: }
8583: hi = (hi >= 0xe0) ? hi - 0x40 : hi;
8584: lo = (lo >= 0x80) ? lo - 0x01 : lo;
8585: hi = ((lo >= 0x9e) ? 1 : 0) + (hi - 0x81) * 2 + 0x21;
8586: lo = ((lo >= 0x9e) ? lo - 0x9e : lo - 0x40) + 0x21;
8587:
8588: return((hi << 8) + lo);
8589: }
8590:
1.1.1.38 root 8591: // AX�e�N�j�J�����t�@�����X�K�C�h 1989
8592: // �t�^10 ���{��g��PRINTER DRIVER NIOS�T�d�l
8593: // 6. �R���g���[���R�[�h�̉��
1.1.1.37 root 8594:
8595: void pcbios_printer_out(int c, UINT8 data)
8596: {
8597: if(pio[c].conv_mode) {
8598: if(pio[c].sjis_hi != 0) {
8599: if(!pio[c].jis_mode) {
8600: printer_out(c, 0x1c);
8601: printer_out(c, 0x26);
8602: pio[c].jis_mode = true;
8603: }
8604: UINT16 jis = pcbios_printer_sjis2jis((pio[c].sjis_hi << 8) | data);
8605: printer_out(c, jis >> 8);
8606: printer_out(c, jis & 0xff);
8607: pio[c].sjis_hi = 0;
8608: } else if(pio[c].esc_buf[0] == 0x1b) {
8609: printer_out(c, data);
8610: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
8611: pio[c].esc_buf[pio[c].esc_len] = data;
8612: }
8613: pio[c].esc_len++;
8614:
8615: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 8616: case 0x33: // 1Bh 33h XX
8617: case 0x4a: // 1Bh 4Ah XX
8618: case 0x4e: // 1Bh 4Eh XX
8619: case 0x51: // 1Bh 51h XX
8620: case 0x55: // 1Bh 55h XX
8621: case 0x6c: // 1Bh 6Ch XX
8622: case 0x71: // 1Bh 71h XX
8623: case 0x72: // 1Bh 72h XX
1.1.1.37 root 8624: if(pio[c].esc_len == 3) {
8625: pio[c].esc_buf[0] = 0x00;
8626: }
8627: break;
1.1.1.38 root 8628: case 0x24: // 1Bh 24h XX XX
8629: case 0x5c: // 1Bh 5Ch XX XX
1.1.1.37 root 8630: if(pio[c].esc_len == 4) {
8631: pio[c].esc_buf[0] = 0x00;
8632: }
8633: break;
1.1.1.38 root 8634: case 0x2a: // 1Bh 2Ah XX XX XX data
1.1.1.37 root 8635: if(pio[c].esc_len >= 3) {
8636: switch(pio[c].esc_buf[2]) {
8637: case 0: case 1: case 2: case 3: case 4: case 6:
8638: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 1) {
8639: pio[c].esc_buf[0] = 0x00;
8640: }
8641: break;
8642: case 32: case 33: case 38: case 39: case 40:
8643: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 3) {
8644: pio[c].esc_buf[0] = 0x00;
8645: }
8646: break;
1.1.1.38 root 8647: case 71: case 72: case 73:
8648: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 6) {
8649: pio[c].esc_buf[0] = 0x00;
8650: }
8651: break;
1.1.1.37 root 8652: default:
8653: pio[c].esc_buf[0] = 0x00;
8654: break;
8655: }
8656: }
8657: break;
1.1.1.38 root 8658: case 0x40: // 1Bh 40h
1.1.1.37 root 8659: if(pio[c].jis_mode) {
8660: printer_out(c, 0x1c);
8661: printer_out(c, 0x2e);
8662: pio[c].jis_mode = false;
8663: }
8664: pio[c].esc_buf[0] = 0x00;
8665: break;
1.1.1.38 root 8666: case 0x42: // 1Bh 42h data 00h
8667: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8668: if(pio[c].esc_len >= 3 && data == 0) {
8669: pio[c].esc_buf[0] = 0x00;
8670: }
8671: break;
1.1.1.38 root 8672: case 0x43: // 1Bh 43h (00h) XX
1.1.1.37 root 8673: if(pio[c].esc_len >= 3 && data != 0) {
8674: pio[c].esc_buf[0] = 0x00;
8675: }
8676: break;
1.1.1.38 root 8677: default: // 1Bh XX
1.1.1.37 root 8678: pio[c].esc_buf[0] = 0x00;
8679: break;
8680: }
8681: } else if(pio[c].esc_buf[0] == 0x1c) {
8682: printer_out(c, data);
8683: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
8684: pio[c].esc_buf[pio[c].esc_len] = data;
8685: }
8686: pio[c].esc_len++;
8687:
8688: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 8689: case 0x21: // 1Ch 21h XX
8690: case 0x2d: // 1Ch 2Dh XX
8691: case 0x57: // 1Ch 57h XX
8692: case 0x6b: // 1Ch 6Bh XX
8693: case 0x72: // 1Ch 72h XX
8694: case 0x78: // 1Ch 78h XX
1.1.1.37 root 8695: if(pio[c].esc_len == 3) {
8696: pio[c].esc_buf[0] = 0x00;
8697: }
8698: break;
1.1.1.38 root 8699: case 0x26: // 1Ch 26h
1.1.1.37 root 8700: pio[c].jis_mode = true;
8701: pio[c].esc_buf[0] = 0x00;
8702: break;
1.1.1.38 root 8703: case 0x2e: // 1Ch 2Eh
1.1.1.37 root 8704: pio[c].jis_mode = false;
8705: pio[c].esc_buf[0] = 0x00;
8706: break;
1.1.1.38 root 8707: case 0x32: // 1Ch 32h XX XX data
1.1.1.37 root 8708: if(pio[c].esc_len == 76) {
8709: pio[c].esc_buf[0] = 0x00;
8710: }
8711: break;
1.1.1.38 root 8712: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8713: if(pio[c].esc_len == 6) {
8714: pio[c].esc_buf[0] = 0x00;
8715: }
8716: break;
1.1.1.38 root 8717: case 0x53: // 1Ch 53h XX XX
8718: case 0x54: // 1Ch 54h XX XX
1.1.1.37 root 8719: if(pio[c].esc_len == 4) {
8720: pio[c].esc_buf[0] = 0x00;
8721: }
8722: break;
1.1.1.38 root 8723: default: // 1Ch XX
1.1.1.37 root 8724: pio[c].esc_buf[0] = 0x00;
8725: break;
8726: }
8727: } else if(data == 0x1b || data == 0x1c) {
8728: printer_out(c, data);
8729: pio[c].esc_buf[0] = data;
8730: pio[c].esc_len = 1;
8731: } else if((data >= 0x80 && data <= 0x9f) || (data >= 0xe0 && data <= 0xff)) {
8732: pio[c].sjis_hi = data;
8733: } else {
8734: if(pio[c].jis_mode) {
8735: printer_out(c, 0x1c);
8736: printer_out(c, 0x2e);
8737: pio[c].jis_mode = false;
8738: }
8739: printer_out(c, data);
8740: }
8741: } else {
8742: if(pio[c].jis_mode) {
8743: printer_out(c, 0x1c);
8744: printer_out(c, 0x2e);
8745: pio[c].jis_mode = false;
8746: }
8747: printer_out(c, data);
8748: }
8749: }
8750:
8751: inline void pcbios_int_17h_00h()
8752: {
8753: if(REG16(DX) < 3) {
8754: pcbios_printer_out(REG16(DX), REG8(AL));
8755: REG8(AH) = 0xd0;
8756: }
8757: }
8758:
8759: inline void pcbios_int_17h_01h()
8760: {
8761: if(REG16(DX) < 3) {
8762: REG8(AH) = 0xd0;
8763: }
8764: }
8765:
8766: inline void pcbios_int_17h_02h()
8767: {
8768: if(REG16(DX) < 3) {
8769: REG8(AH) = 0xd0;
8770: }
8771: }
8772:
8773: inline void pcbios_int_17h_03h()
8774: {
8775: switch(REG8(AL)) {
8776: case 0x00:
8777: if(REG16(DX) < 3) {
8778: if(pio[REG16(DX)].jis_mode) {
8779: printer_out(REG16(DX), 0x1c);
8780: printer_out(REG16(DX), 0x2e);
8781: pio[REG16(DX)].jis_mode = false;
8782: }
8783: for(UINT16 i = 0; i < REG16(CX); i++) {
8784: printer_out(REG16(DX), mem[SREG_BASE(ES) + REG16(BX) + i]);
8785: }
8786: REG16(CX) = 0x0000;
8787: REG8(AH) = 0xd0;
8788: }
8789: break;
8790: default:
8791: 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));
8792: break;
8793: }
8794: }
8795:
8796: inline void pcbios_int_17h_50h()
8797: {
8798: switch(REG8(AL)) {
8799: case 0x00:
8800: if(REG16(DX) < 3) {
8801: if(REG16(BX) = 0x0001) {
8802: pio[REG16(DX)].conv_mode = false;
8803: REG8(AL) = 0x00;
8804: } else if(REG16(BX) = 0x0051) {
8805: pio[REG16(DX)].conv_mode = true;
8806: REG8(AL) = 0x00;
8807: } else {
8808: REG8(AL) = 0x01;
8809: }
8810: } else {
8811: REG8(AL) = 0x02;
8812: }
8813: break;
8814: case 0x01:
8815: if(REG16(DX) < 3) {
8816: if(pio[REG16(DX)].conv_mode) {
8817: REG16(BX) = 0x0051;
8818: } else {
8819: REG16(BX) = 0x0001;
8820: }
8821: REG8(AL) = 0x00;
8822: } else {
8823: REG8(AL) = 0x02;
8824: }
8825: break;
8826: default:
8827: 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));
8828: break;
8829: }
8830: }
8831:
8832: inline void pcbios_int_17h_51h()
8833: {
8834: if(REG8(DH) >= 0x21 && REG8(DH) <= 0x7e && REG8(DL) >= 0x21 && REG8(DL) <= 0x7e) {
8835: REG16(DX) = pcbios_printer_jis2sjis(REG16(DX));
8836: } else {
8837: REG16(DX) = 0x0000;
8838: }
8839: }
8840:
8841: inline void pcbios_int_17h_52h()
8842: {
8843: if(((REG8(DH) >= 0x81 && REG8(DH) <= 0x9f) || (REG8(DH) >= 0xe0 && REG8(DH) <= 0xfc)) && (REG8(DL) >= 0x40 && REG8(DL) <= 0xfc && REG8(DL) != 0x7f)) {
8844: REG16(DX) = pcbios_printer_sjis2jis(REG16(DX));
8845: } else {
8846: REG16(DX) = 0x0000;
8847: }
8848: }
8849:
8850: inline void pcbios_int_17h_84h()
8851: {
8852: if(REG16(DX) < 3) {
8853: if(pio[REG16(DX)].jis_mode) {
8854: printer_out(REG16(DX), 0x1c);
8855: printer_out(REG16(DX), 0x2e);
8856: pio[REG16(DX)].jis_mode = false;
8857: }
8858: printer_out(REG16(DX), REG8(AL));
8859: REG8(AH) = 0xd0;
8860: }
8861: }
8862:
8863: inline void pcbios_int_17h_85h()
8864: {
8865: pio[0].conv_mode = (REG8(AL) == 0x00);
8866: }
8867:
1.1 root 8868: inline void pcbios_int_1ah_00h()
8869: {
1.1.1.19 root 8870: pcbios_update_daily_timer_counter(timeGetTime());
8871: REG16(CX) = *(UINT16 *)(mem + 0x46e);
8872: REG16(DX) = *(UINT16 *)(mem + 0x46c);
8873: REG8(AL) = mem[0x470];
8874: mem[0x470] = 0;
1.1 root 8875: }
8876:
8877: inline int to_bcd(int t)
8878: {
8879: int u = (t % 100) / 10;
8880: return (u << 4) | (t % 10);
8881: }
8882:
8883: inline void pcbios_int_1ah_02h()
8884: {
8885: SYSTEMTIME time;
8886:
8887: GetLocalTime(&time);
8888: REG8(CH) = to_bcd(time.wHour);
8889: REG8(CL) = to_bcd(time.wMinute);
8890: REG8(DH) = to_bcd(time.wSecond);
8891: REG8(DL) = 0x00;
8892: }
8893:
8894: inline void pcbios_int_1ah_04h()
8895: {
8896: SYSTEMTIME time;
8897:
8898: GetLocalTime(&time);
8899: REG8(CH) = to_bcd(time.wYear / 100);
8900: REG8(CL) = to_bcd(time.wYear);
8901: REG8(DH) = to_bcd(time.wMonth);
8902: REG8(DL) = to_bcd(time.wDay);
8903: }
8904:
8905: inline void pcbios_int_1ah_0ah()
8906: {
8907: SYSTEMTIME time;
8908: FILETIME file_time;
8909: WORD dos_date, dos_time;
8910:
8911: GetLocalTime(&time);
8912: SystemTimeToFileTime(&time, &file_time);
8913: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
8914: REG16(CX) = dos_date;
8915: }
8916:
8917: // msdos system call
8918:
1.1.1.43 root 8919: inline void msdos_int_21h_56h(int lfn);
8920:
1.1 root 8921: inline void msdos_int_21h_00h()
8922: {
1.1.1.3 root 8923: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 8924: }
8925:
1.1.1.35 root 8926: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID)
1.1 root 8927: {
8928: REG8(AL) = msdos_getche();
1.1.1.33 root 8929: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8930:
1.1.1.35 root 8931: #ifdef USE_SERVICE_THREAD
8932: service_exit = true;
8933: #endif
8934: return(0);
8935: }
8936:
8937: inline void msdos_int_21h_01h()
8938: {
8939: #ifdef USE_SERVICE_THREAD
1.1.1.51 root 8940: if(!in_service && !in_service_29h &&
8941: *(UINT16 *)(mem + 4 * 0x29 + 0) == 0x29 &&
1.1.1.50 root 8942: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
8943: // msdos_putch() will be used in this service
8944: // if int 29h is hooked, run this service in main thread to call int 29h
8945: start_service_loop(msdos_int_21h_01h_thread);
8946: } else {
8947: #endif
8948: msdos_int_21h_01h_thread(NULL);
8949: REQUEST_HARDWRE_UPDATE();
8950: #ifdef USE_SERVICE_THREAD
8951: }
1.1.1.35 root 8952: #endif
1.1 root 8953: }
8954:
8955: inline void msdos_int_21h_02h()
8956: {
1.1.1.33 root 8957: UINT8 data = REG8(DL);
8958: msdos_putch(data);
8959: REG8(AL) = data;
8960: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8961: }
8962:
8963: inline void msdos_int_21h_03h()
8964: {
8965: REG8(AL) = msdos_aux_in();
8966: }
8967:
8968: inline void msdos_int_21h_04h()
8969: {
8970: msdos_aux_out(REG8(DL));
8971: }
8972:
8973: inline void msdos_int_21h_05h()
8974: {
8975: msdos_prn_out(REG8(DL));
8976: }
8977:
8978: inline void msdos_int_21h_06h()
8979: {
8980: if(REG8(DL) == 0xff) {
8981: if(msdos_kbhit()) {
8982: REG8(AL) = msdos_getch();
1.1.1.3 root 8983: #if defined(HAS_I386)
8984: m_ZF = 0;
8985: #else
8986: m_ZeroVal = 1;
8987: #endif
1.1 root 8988: } else {
8989: REG8(AL) = 0;
1.1.1.3 root 8990: #if defined(HAS_I386)
8991: m_ZF = 1;
8992: #else
8993: m_ZeroVal = 0;
8994: #endif
1.1.1.14 root 8995: maybe_idle();
1.1 root 8996: }
8997: } else {
1.1.1.33 root 8998: UINT8 data = REG8(DL);
8999: msdos_putch(data);
9000: REG8(AL) = data;
1.1 root 9001: }
9002: }
9003:
1.1.1.35 root 9004: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID)
1.1 root 9005: {
9006: REG8(AL) = msdos_getch();
1.1.1.26 root 9007:
1.1.1.35 root 9008: #ifdef USE_SERVICE_THREAD
9009: service_exit = true;
9010: #endif
9011: return(0);
1.1 root 9012: }
9013:
1.1.1.35 root 9014: inline void msdos_int_21h_07h()
9015: {
9016: #ifdef USE_SERVICE_THREAD
1.1.1.51 root 9017: if(!in_service && !in_service_29h) {
9018: start_service_loop(msdos_int_21h_07h_thread);
9019: } else {
9020: #endif
9021: msdos_int_21h_07h_thread(NULL);
9022: REQUEST_HARDWRE_UPDATE();
9023: #ifdef USE_SERVICE_THREAD
9024: }
1.1.1.35 root 9025: #endif
9026: }
9027:
9028: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID)
1.1 root 9029: {
9030: REG8(AL) = msdos_getch();
1.1.1.33 root 9031: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 9032:
1.1.1.35 root 9033: #ifdef USE_SERVICE_THREAD
9034: service_exit = true;
9035: #endif
9036: return(0);
9037: }
9038:
9039: inline void msdos_int_21h_08h()
9040: {
9041: #ifdef USE_SERVICE_THREAD
1.1.1.51 root 9042: if(!in_service && !in_service_29h) {
9043: start_service_loop(msdos_int_21h_08h_thread);
9044: } else {
9045: #endif
9046: msdos_int_21h_08h_thread(NULL);
9047: REQUEST_HARDWRE_UPDATE();
9048: #ifdef USE_SERVICE_THREAD
9049: }
1.1.1.35 root 9050: #endif
1.1 root 9051: }
9052:
9053: inline void msdos_int_21h_09h()
9054: {
1.1.1.21 root 9055: msdos_stdio_reopen();
9056:
1.1.1.20 root 9057: process_t *process = msdos_process_info_get(current_psp);
9058: int fd = msdos_psp_get_file_table(1, current_psp);
9059:
1.1.1.14 root 9060: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
9061: int len = 0;
1.1 root 9062:
1.1.1.14 root 9063: while(str[len] != '$' && len < 0x10000) {
9064: len++;
9065: }
1.1.1.20 root 9066: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 9067: // stdout is redirected to file
1.1.1.20 root 9068: msdos_write(fd, str, len);
1.1 root 9069: } else {
9070: for(int i = 0; i < len; i++) {
1.1.1.14 root 9071: msdos_putch(str[i]);
1.1 root 9072: }
9073: }
1.1.1.33 root 9074: REG8(AL) = '$';
9075: ctrl_break_detected = ctrl_break_pressed;
1.1 root 9076: }
9077:
1.1.1.35 root 9078: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID)
1.1 root 9079: {
1.1.1.3 root 9080: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 9081: int max = mem[ofs] - 1;
9082: UINT8 *buf = mem + ofs + 2;
9083: int chr, p = 0;
9084:
9085: while((chr = msdos_getch()) != 0x0d) {
1.1.1.33 root 9086: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 9087: p = 0;
1.1.1.33 root 9088: msdos_putch(0x03);
9089: msdos_putch(0x0d);
9090: msdos_putch(0x0a);
1.1.1.26 root 9091: break;
1.1.1.33 root 9092: } else if(ctrl_break_pressed) {
9093: // skip this byte
1.1.1.26 root 9094: } else if(chr == 0x00) {
1.1 root 9095: // skip 2nd byte
9096: msdos_getch();
9097: } else if(chr == 0x08) {
9098: // back space
9099: if(p > 0) {
9100: p--;
1.1.1.20 root 9101: if(msdos_ctrl_code_check(buf[p])) {
1.1.1.34 root 9102: msdos_putch(0x08);
9103: msdos_putch(0x08);
9104: msdos_putch(0x20);
9105: msdos_putch(0x20);
9106: msdos_putch(0x08);
9107: msdos_putch(0x08);
1.1.1.36 root 9108: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
9109: p--;
9110: msdos_putch(0x08);
9111: msdos_putch(0x08);
9112: msdos_putch(0x20);
9113: msdos_putch(0x20);
9114: msdos_putch(0x08);
9115: msdos_putch(0x08);
1.1.1.34 root 9116: } else {
9117: msdos_putch(0x08);
9118: msdos_putch(0x20);
9119: msdos_putch(0x08);
9120: }
9121: }
9122: } else if(chr == 0x1b) {
9123: // escape
9124: while(p > 0) {
9125: p--;
9126: if(msdos_ctrl_code_check(buf[p])) {
9127: msdos_putch(0x08);
9128: msdos_putch(0x08);
9129: msdos_putch(0x20);
9130: msdos_putch(0x20);
9131: msdos_putch(0x08);
9132: msdos_putch(0x08);
1.1.1.20 root 9133: } else {
1.1.1.34 root 9134: msdos_putch(0x08);
9135: msdos_putch(0x20);
9136: msdos_putch(0x08);
1.1.1.20 root 9137: }
1.1 root 9138: }
9139: } else if(p < max) {
9140: buf[p++] = chr;
9141: msdos_putch(chr);
9142: }
9143: }
9144: buf[p] = 0x0d;
9145: mem[ofs + 1] = p;
1.1.1.33 root 9146: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 9147:
1.1.1.35 root 9148: #ifdef USE_SERVICE_THREAD
9149: service_exit = true;
9150: #endif
9151: return(0);
9152: }
9153:
9154: inline void msdos_int_21h_0ah()
9155: {
9156: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) {
9157: #ifdef USE_SERVICE_THREAD
1.1.1.51 root 9158: if(!in_service && !in_service_29h &&
9159: *(UINT16 *)(mem + 4 * 0x29 + 0) == 0x29 &&
1.1.1.50 root 9160: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
9161: // msdos_putch() will be used in this service
9162: // if int 29h is hooked, run this service in main thread to call int 29h
9163: start_service_loop(msdos_int_21h_0ah_thread);
9164: } else {
9165: #endif
9166: msdos_int_21h_0ah_thread(NULL);
9167: REQUEST_HARDWRE_UPDATE();
9168: #ifdef USE_SERVICE_THREAD
9169: }
1.1.1.35 root 9170: #endif
9171: }
1.1 root 9172: }
9173:
9174: inline void msdos_int_21h_0bh()
9175: {
9176: if(msdos_kbhit()) {
9177: REG8(AL) = 0xff;
9178: } else {
9179: REG8(AL) = 0x00;
1.1.1.14 root 9180: maybe_idle();
1.1 root 9181: }
1.1.1.33 root 9182: ctrl_break_detected = ctrl_break_pressed;
1.1 root 9183: }
9184:
9185: inline void msdos_int_21h_0ch()
9186: {
9187: // clear key buffer
1.1.1.21 root 9188: msdos_stdio_reopen();
9189:
1.1.1.20 root 9190: process_t *process = msdos_process_info_get(current_psp);
9191: int fd = msdos_psp_get_file_table(0, current_psp);
9192:
9193: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 9194: // stdin is redirected to file
9195: } else {
9196: while(msdos_kbhit()) {
9197: msdos_getch();
9198: }
9199: }
9200:
9201: switch(REG8(AL)) {
9202: case 0x01:
9203: msdos_int_21h_01h();
9204: break;
9205: case 0x06:
9206: msdos_int_21h_06h();
9207: break;
9208: case 0x07:
9209: msdos_int_21h_07h();
9210: break;
9211: case 0x08:
9212: msdos_int_21h_08h();
9213: break;
9214: case 0x0a:
9215: msdos_int_21h_0ah();
9216: break;
9217: default:
1.1.1.48 root 9218: // the buffer is flushed but no input is attempted
1.1 root 9219: break;
9220: }
9221: }
9222:
9223: inline void msdos_int_21h_0dh()
9224: {
9225: }
9226:
9227: inline void msdos_int_21h_0eh()
9228: {
9229: if(REG8(DL) < 26) {
9230: _chdrive(REG8(DL) + 1);
9231: msdos_cds_update(REG8(DL));
1.1.1.23 root 9232: msdos_sda_update(current_psp);
1.1 root 9233: }
9234: REG8(AL) = 26; // zdrive
9235: }
9236:
1.1.1.14 root 9237: inline void msdos_int_21h_0fh()
9238: {
9239: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9240: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.45 root 9241: const char *path = msdos_fcb_path(fcb);
1.1.1.14 root 9242: HANDLE hFile = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.16 root 9243:
1.1.1.14 root 9244: if(hFile == INVALID_HANDLE_VALUE) {
9245: REG8(AL) = 0xff;
9246: } else {
9247: REG8(AL) = 0;
9248: fcb->current_block = 0;
9249: fcb->record_size = 128;
9250: fcb->file_size = GetFileSize(hFile, NULL);
9251: fcb->handle = hFile;
9252: fcb->cur_record = 0;
9253: }
9254: }
9255:
9256: inline void msdos_int_21h_10h()
9257: {
9258: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9259: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9260:
9261: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
9262: }
9263:
1.1 root 9264: inline void msdos_int_21h_11h()
9265: {
1.1.1.3 root 9266: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9267: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9268:
9269: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9270: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9271: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
9272: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1.1.45 root 9273: const char *path = msdos_fcb_path(fcb);
1.1 root 9274: WIN32_FIND_DATA fd;
9275:
1.1.1.13 root 9276: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
9277: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9278: FindClose(dtainfo->find_handle);
9279: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9280: }
9281: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 9282: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
9283: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 9284:
1.1.1.14 root 9285: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
9286: dtainfo->allowable_mask &= ~8;
1.1 root 9287: }
1.1.1.14 root 9288: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
9289: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9290: !msdos_find_file_has_8dot3name(&fd)) {
9291: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9292: FindClose(dtainfo->find_handle);
9293: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9294: break;
9295: }
9296: }
9297: }
1.1.1.13 root 9298: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9299: if(ext_fcb->flag == 0xff) {
9300: ext_find->flag = 0xff;
9301: memset(ext_find->reserved, 0, 5);
9302: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9303: }
9304: find->drive = _getdrive();
1.1.1.13 root 9305: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 9306: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9307: find->nt_res = 0;
9308: msdos_find_file_conv_local_time(&fd);
9309: find->create_time_ms = 0;
9310: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9311: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9312: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9313: find->cluster_hi = find->cluster_lo = 0;
9314: find->file_size = fd.nFileSizeLow;
9315: REG8(AL) = 0x00;
1.1.1.14 root 9316: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9317: if(ext_fcb->flag == 0xff) {
9318: ext_find->flag = 0xff;
9319: memset(ext_find->reserved, 0, 5);
9320: ext_find->attribute = 8;
9321: }
9322: find->drive = _getdrive();
9323: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
9324: find->attribute = 8;
9325: find->nt_res = 0;
9326: msdos_find_file_conv_local_time(&fd);
9327: find->create_time_ms = 0;
9328: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9329: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9330: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9331: find->cluster_hi = find->cluster_lo = 0;
9332: find->file_size = 0;
1.1.1.14 root 9333: dtainfo->allowable_mask &= ~8;
1.1 root 9334: REG8(AL) = 0x00;
9335: } else {
9336: REG8(AL) = 0xff;
9337: }
9338: }
9339:
9340: inline void msdos_int_21h_12h()
9341: {
1.1.1.3 root 9342: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 9343: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9344:
9345: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9346: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9347: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
9348: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9349: WIN32_FIND_DATA fd;
9350:
1.1.1.13 root 9351: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
9352: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9353: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 9354: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9355: !msdos_find_file_has_8dot3name(&fd)) {
9356: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9357: FindClose(dtainfo->find_handle);
9358: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9359: break;
9360: }
9361: }
9362: } else {
1.1.1.13 root 9363: FindClose(dtainfo->find_handle);
9364: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9365: }
9366: }
1.1.1.13 root 9367: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9368: if(ext_fcb->flag == 0xff) {
9369: ext_find->flag = 0xff;
9370: memset(ext_find->reserved, 0, 5);
9371: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9372: }
9373: find->drive = _getdrive();
1.1.1.13 root 9374: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 9375: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9376: find->nt_res = 0;
9377: msdos_find_file_conv_local_time(&fd);
9378: find->create_time_ms = 0;
9379: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9380: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9381: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9382: find->cluster_hi = find->cluster_lo = 0;
9383: find->file_size = fd.nFileSizeLow;
9384: REG8(AL) = 0x00;
1.1.1.14 root 9385: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9386: if(ext_fcb->flag == 0xff) {
9387: ext_find->flag = 0xff;
9388: memset(ext_find->reserved, 0, 5);
9389: ext_find->attribute = 8;
9390: }
9391: find->drive = _getdrive();
9392: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
9393: find->attribute = 8;
9394: find->nt_res = 0;
9395: msdos_find_file_conv_local_time(&fd);
9396: find->create_time_ms = 0;
9397: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9398: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9399: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9400: find->cluster_hi = find->cluster_lo = 0;
9401: find->file_size = 0;
1.1.1.14 root 9402: dtainfo->allowable_mask &= ~8;
1.1 root 9403: REG8(AL) = 0x00;
9404: } else {
9405: REG8(AL) = 0xff;
9406: }
9407: }
9408:
9409: inline void msdos_int_21h_13h()
9410: {
1.1.1.3 root 9411: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 9412: REG8(AL) = 0xff;
9413: } else {
9414: REG8(AL) = 0x00;
9415: }
9416: }
9417:
1.1.1.16 root 9418: inline void msdos_int_21h_14h()
9419: {
9420: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9421: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9422: process_t *process = msdos_process_info_get(current_psp);
9423: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9424: DWORD num = 0;
9425:
9426: memset(mem + dta_laddr, 0, fcb->record_size);
9427: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9428: REG8(AL) = 1;
9429: } else {
9430: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
9431: fcb->current_block = (position & 0xffffff) / fcb->record_size;
9432: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
9433: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
9434: }
9435: }
9436:
9437: inline void msdos_int_21h_15h()
1.1.1.14 root 9438: {
9439: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9440: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 9441: process_t *process = msdos_process_info_get(current_psp);
9442: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9443: DWORD num = 0;
1.1.1.14 root 9444:
1.1.1.16 root 9445: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9446: REG8(AL) = 1;
9447: } else {
9448: fcb->file_size = GetFileSize(fcb->handle, NULL);
9449: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
9450: fcb->current_block = (position & 0xffffff) / fcb->record_size;
9451: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
9452: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
9453: }
9454: }
9455:
9456: inline void msdos_int_21h_16h()
9457: {
9458: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9459: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.45 root 9460: const char *path = msdos_fcb_path(fcb);
1.1.1.14 root 9461: HANDLE hFile = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, ext_fcb->flag == 0xff ? ext_fcb->attribute : FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.16 root 9462:
1.1.1.14 root 9463: if(hFile == INVALID_HANDLE_VALUE) {
9464: REG8(AL) = 0xff;
9465: } else {
9466: REG8(AL) = 0;
9467: fcb->current_block = 0;
9468: fcb->record_size = 128;
9469: fcb->file_size = 0;
9470: fcb->handle = hFile;
9471: fcb->cur_record = 0;
9472: }
9473: }
9474:
1.1.1.16 root 9475: inline void msdos_int_21h_17h()
9476: {
9477: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9478: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
1.1.1.45 root 9479: // const char *path_src = msdos_fcb_path(fcb_src);
9480: char path_src[MAX_PATH];
9481: strcpy(path_src, msdos_fcb_path(fcb_src));
9482:
1.1.1.16 root 9483: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
9484: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
1.1.1.45 root 9485: // const char *path_dst = msdos_fcb_path(fcb_dst);
9486: char path_dst[MAX_PATH];
9487: strcpy(path_dst, msdos_fcb_path(fcb_dst));
1.1.1.16 root 9488:
9489: if(rename(path_src, path_dst)) {
9490: REG8(AL) = 0xff;
9491: } else {
9492: REG8(AL) = 0;
9493: }
9494: }
9495:
1.1 root 9496: inline void msdos_int_21h_18h()
9497: {
9498: REG8(AL) = 0x00;
9499: }
9500:
9501: inline void msdos_int_21h_19h()
9502: {
9503: REG8(AL) = _getdrive() - 1;
9504: }
9505:
9506: inline void msdos_int_21h_1ah()
9507: {
9508: process_t *process = msdos_process_info_get(current_psp);
9509:
9510: process->dta.w.l = REG16(DX);
1.1.1.3 root 9511: process->dta.w.h = SREG(DS);
1.1.1.23 root 9512: msdos_sda_update(current_psp);
1.1 root 9513: }
9514:
9515: inline void msdos_int_21h_1bh()
9516: {
9517: int drive_num = _getdrive() - 1;
9518: UINT16 seg, ofs;
9519:
9520: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9521: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9522: REG8(AL) = dpb->highest_sector_num + 1;
9523: REG16(CX) = dpb->bytes_per_sector;
9524: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 9525: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 9526: } else {
9527: REG8(AL) = 0xff;
1.1.1.3 root 9528: m_CF = 1;
1.1 root 9529: }
9530:
9531: }
9532:
9533: inline void msdos_int_21h_1ch()
9534: {
1.1.1.41 root 9535: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
1.1 root 9536: UINT16 seg, ofs;
9537:
9538: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9539: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9540: REG8(AL) = dpb->highest_sector_num + 1;
9541: REG16(CX) = dpb->bytes_per_sector;
9542: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 9543: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 9544: } else {
9545: REG8(AL) = 0xff;
1.1.1.3 root 9546: m_CF = 1;
1.1 root 9547: }
9548:
9549: }
9550:
9551: inline void msdos_int_21h_1dh()
9552: {
9553: REG8(AL) = 0;
9554: }
9555:
9556: inline void msdos_int_21h_1eh()
9557: {
9558: REG8(AL) = 0;
9559: }
9560:
9561: inline void msdos_int_21h_1fh()
9562: {
9563: int drive_num = _getdrive() - 1;
9564: UINT16 seg, ofs;
9565:
9566: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9567: REG8(AL) = 0;
1.1.1.3 root 9568: SREG(DS) = seg;
9569: i386_load_segment_descriptor(DS);
1.1 root 9570: REG16(BX) = ofs;
9571: } else {
9572: REG8(AL) = 0xff;
1.1.1.3 root 9573: m_CF = 1;
1.1 root 9574: }
9575: }
9576:
9577: inline void msdos_int_21h_20h()
9578: {
9579: REG8(AL) = 0;
9580: }
9581:
1.1.1.14 root 9582: inline void msdos_int_21h_21h()
9583: {
9584: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9585: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9586:
9587: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9588: REG8(AL) = 1;
9589: } else {
9590: process_t *process = msdos_process_info_get(current_psp);
9591: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9592: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 9593: DWORD num = 0;
1.1.1.14 root 9594: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9595: REG8(AL) = 1;
9596: } else {
9597: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9598: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 9599: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 9600: }
9601: }
9602: }
9603:
9604: inline void msdos_int_21h_22h()
9605: {
9606: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9607: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9608:
9609: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9610: REG8(AL) = 0xff;
9611: } else {
9612: process_t *process = msdos_process_info_get(current_psp);
9613: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 9614: DWORD num = 0;
1.1.1.14 root 9615: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
9616: fcb->file_size = GetFileSize(fcb->handle, NULL);
9617: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9618: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 9619: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 9620: }
9621: }
9622:
1.1.1.16 root 9623: inline void msdos_int_21h_23h()
9624: {
9625: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9626: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.45 root 9627: const char *path = msdos_fcb_path(fcb);
1.1.1.16 root 9628: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9629:
9630: if(hFile == INVALID_HANDLE_VALUE) {
9631: REG8(AL) = 0xff;
9632: } else {
9633: UINT32 size = GetFileSize(hFile, NULL);
9634: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
9635: REG8(AL) = 0;
9636: }
9637: }
9638:
9639: inline void msdos_int_21h_24h()
9640: {
9641: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9642: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9643:
9644: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
9645: }
9646:
1.1 root 9647: inline void msdos_int_21h_25h()
9648: {
9649: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 9650: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 9651: }
9652:
9653: inline void msdos_int_21h_26h()
9654: {
9655: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
9656:
9657: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
1.1.1.48 root 9658: psp->first_mcb = REG16(DX) + (PSP_SIZE >> 4);
1.1 root 9659: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
9660: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
9661: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
9662: psp->parent_psp = 0;
9663: }
9664:
1.1.1.16 root 9665: inline void msdos_int_21h_27h()
9666: {
9667: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9668: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9669:
9670: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9671: REG8(AL) = 1;
9672: } else {
9673: process_t *process = msdos_process_info_get(current_psp);
9674: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9675: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
9676: DWORD num = 0;
9677: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
9678: REG8(AL) = 1;
9679: } else {
9680: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9681: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9682: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
9683: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9684: }
9685: }
9686: }
9687:
9688: inline void msdos_int_21h_28h()
9689: {
9690: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9691: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9692:
9693: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9694: REG8(AL) = 0xff;
9695: } else {
9696: process_t *process = msdos_process_info_get(current_psp);
9697: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9698: DWORD num = 0;
9699: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
9700: fcb->file_size = GetFileSize(fcb->handle, NULL);
9701: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9702: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9703: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
9704: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9705: }
9706: }
9707:
1.1 root 9708: inline void msdos_int_21h_29h()
9709: {
1.1.1.20 root 9710: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
9711: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 9712: UINT8 drv = 0;
9713: char sep_chars[] = ":.;,=+";
9714: char end_chars[] = "\\<>|/\"[]";
9715: char spc_chars[] = " \t";
9716:
1.1.1.20 root 9717: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
9718: buffer[1023] = 0;
9719: memset(name, 0x20, sizeof(name));
9720: memset(ext, 0x20, sizeof(ext));
9721:
1.1 root 9722: if(REG8(AL) & 1) {
1.1.1.20 root 9723: ofs += strspn((char *)(buffer + ofs), spc_chars);
9724: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 9725: ofs++;
9726: }
9727: }
1.1.1.20 root 9728: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 9729:
1.1.1.24 root 9730: if(buffer[ofs + 1] == ':') {
9731: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
9732: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 9733: ofs += 2;
1.1.1.24 root 9734: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9735: ofs++;
9736: }
9737: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
9738: drv = buffer[ofs] - 'A' + 1;
1.1 root 9739: ofs += 2;
1.1.1.24 root 9740: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9741: ofs++;
9742: }
1.1 root 9743: }
9744: }
1.1.1.20 root 9745: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9746: UINT8 c = buffer[ofs];
9747: if(is_kanji) {
9748: is_kanji = 0;
9749: } else if(msdos_lead_byte_check(c)) {
9750: is_kanji = 1;
9751: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9752: break;
9753: } else if(c >= 'a' && c <= 'z') {
9754: c -= 0x20;
9755: }
9756: ofs++;
9757: name[i] = c;
9758: }
1.1.1.20 root 9759: if(buffer[ofs] == '.') {
1.1 root 9760: ofs++;
1.1.1.20 root 9761: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9762: UINT8 c = buffer[ofs];
9763: if(is_kanji) {
9764: is_kanji = 0;
9765: } else if(msdos_lead_byte_check(c)) {
9766: is_kanji = 1;
9767: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9768: break;
9769: } else if(c >= 'a' && c <= 'z') {
9770: c -= 0x20;
9771: }
9772: ofs++;
9773: ext[i] = c;
9774: }
9775: }
1.1.1.20 root 9776: int si = REG16(SI) + ofs;
1.1.1.3 root 9777: int ds = SREG(DS);
1.1 root 9778: while(si > 0xffff) {
9779: si -= 0x10;
9780: ds++;
9781: }
9782: REG16(SI) = si;
1.1.1.3 root 9783: SREG(DS) = ds;
9784: i386_load_segment_descriptor(DS);
1.1 root 9785:
1.1.1.3 root 9786: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 9787: if(!(REG8(AL) & 2) || drv != 0) {
9788: fcb[0] = drv;
9789: }
9790: if(!(REG8(AL) & 4) || name[0] != 0x20) {
9791: memcpy(fcb + 1, name, 8);
9792: }
9793: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
9794: memcpy(fcb + 9, ext, 3);
9795: }
9796: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 9797: if(fcb[i] == '*') {
9798: found_star = 1;
9799: }
9800: if(found_star) {
9801: fcb[i] = '?';
9802: }
9803: }
1.1.1.20 root 9804: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 9805: if(fcb[i] == '*') {
9806: found_star = 1;
9807: }
9808: if(found_star) {
9809: fcb[i] = '?';
9810: }
9811: }
9812:
1.1.1.44 root 9813: if(drv == 0 || msdos_is_valid_drive(drv - 1)) {
1.1 root 9814: if(memchr(fcb + 1, '?', 8 + 3)) {
9815: REG8(AL) = 0x01;
1.1.1.20 root 9816: } else {
9817: REG8(AL) = 0x00;
1.1 root 9818: }
9819: } else {
9820: REG8(AL) = 0xff;
9821: }
9822: }
9823:
9824: inline void msdos_int_21h_2ah()
9825: {
9826: SYSTEMTIME sTime;
9827:
9828: GetLocalTime(&sTime);
9829: REG16(CX) = sTime.wYear;
9830: REG8(DH) = (UINT8)sTime.wMonth;
9831: REG8(DL) = (UINT8)sTime.wDay;
9832: REG8(AL) = (UINT8)sTime.wDayOfWeek;
9833: }
9834:
9835: inline void msdos_int_21h_2bh()
9836: {
1.1.1.14 root 9837: REG8(AL) = 0xff;
1.1 root 9838: }
9839:
9840: inline void msdos_int_21h_2ch()
9841: {
9842: SYSTEMTIME sTime;
9843:
9844: GetLocalTime(&sTime);
9845: REG8(CH) = (UINT8)sTime.wHour;
9846: REG8(CL) = (UINT8)sTime.wMinute;
9847: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 9848: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 9849: }
9850:
9851: inline void msdos_int_21h_2dh()
9852: {
9853: REG8(AL) = 0x00;
9854: }
9855:
9856: inline void msdos_int_21h_2eh()
9857: {
9858: process_t *process = msdos_process_info_get(current_psp);
9859:
9860: process->verify = REG8(AL);
9861: }
9862:
9863: inline void msdos_int_21h_2fh()
9864: {
9865: process_t *process = msdos_process_info_get(current_psp);
9866:
9867: REG16(BX) = process->dta.w.l;
1.1.1.3 root 9868: SREG(ES) = process->dta.w.h;
9869: i386_load_segment_descriptor(ES);
1.1 root 9870: }
9871:
9872: inline void msdos_int_21h_30h()
9873: {
9874: // Version Flag / OEM
1.1.1.27 root 9875: if(REG8(AL) == 0x01) {
1.1.1.29 root 9876: #ifdef SUPPORT_HMA
9877: REG16(BX) = 0x0000;
9878: #else
9879: REG16(BX) = 0x1000; // DOS is in HMA
9880: #endif
1.1 root 9881: } else {
1.1.1.27 root 9882: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
9883: // but this is not correct on Windows 98 SE
9884: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
9885: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 9886: }
1.1.1.27 root 9887: REG16(CX) = 0x0000;
1.1.1.30 root 9888: REG8(AL) = dos_major_version; // 7
9889: REG8(AH) = dos_minor_version; // 10
1.1 root 9890: }
9891:
9892: inline void msdos_int_21h_31h()
9893: {
1.1.1.29 root 9894: try {
9895: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9896: } catch(...) {
9897: // recover the broken mcb
9898: int mcb_seg = current_psp - 1;
9899: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 9900:
1.1.1.29 root 9901: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 9902: mcb->mz = 'M';
9903: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
9904:
1.1.1.29 root 9905: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 9906: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 9907: } else {
1.1.1.39 root 9908: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 9909: }
9910: } else {
9911: mcb->mz = 'Z';
1.1.1.30 root 9912: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 9913: }
9914: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9915: }
1.1 root 9916: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
9917: }
9918:
9919: inline void msdos_int_21h_32h()
9920: {
9921: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
9922: UINT16 seg, ofs;
9923:
9924: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9925: REG8(AL) = 0;
1.1.1.3 root 9926: SREG(DS) = seg;
9927: i386_load_segment_descriptor(DS);
1.1 root 9928: REG16(BX) = ofs;
9929: } else {
9930: REG8(AL) = 0xff;
1.1.1.3 root 9931: m_CF = 1;
1.1 root 9932: }
9933: }
9934:
9935: inline void msdos_int_21h_33h()
9936: {
9937: char path[MAX_PATH];
1.1.1.48 root 9938: char drive = 3; // C:
1.1 root 9939:
9940: switch(REG8(AL)) {
9941: case 0x00:
1.1.1.33 root 9942: REG8(DL) = ctrl_break_checking;
1.1 root 9943: break;
9944: case 0x01:
1.1.1.33 root 9945: ctrl_break_checking = REG8(DL);
9946: break;
9947: case 0x02:
9948: {
9949: UINT8 old = ctrl_break_checking;
9950: ctrl_break_checking = REG8(DL);
9951: REG8(DL) = old;
9952: }
9953: break;
9954: case 0x03:
9955: case 0x04:
9956: // DOS 4.0+ - Unused
1.1 root 9957: break;
9958: case 0x05:
1.1.1.48 root 9959: if(GetSystemDirectory(path, MAX_PATH) != 0) {
9960: if(path[0] >= 'a' && path[0] <= 'z') {
9961: drive = path[0] - 'a' + 1;
9962: } else if(path[0] >= 'A' && path[0] <= 'Z') {
9963: drive = path[0] - 'A' + 1;
9964: }
1.1 root 9965: }
1.1.1.48 root 9966: REG8(DL) = (UINT8)drive;
1.1 root 9967: break;
9968: case 0x06:
1.1.1.2 root 9969: // MS-DOS version (7.10)
1.1 root 9970: REG8(BL) = 7;
1.1.1.2 root 9971: REG8(BH) = 10;
1.1 root 9972: REG8(DL) = 0;
1.1.1.29 root 9973: #ifdef SUPPORT_HMA
9974: REG8(DH) = 0x00;
9975: #else
9976: REG8(DH) = 0x10; // DOS is in HMA
9977: #endif
1.1 root 9978: break;
1.1.1.6 root 9979: case 0x07:
9980: if(REG8(DL) == 0) {
9981: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
9982: } else if(REG8(DL) == 1) {
9983: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
9984: }
9985: break;
1.1 root 9986: default:
1.1.1.22 root 9987: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 9988: // REG16(AX) = 0x01;
9989: // m_CF = 1;
9990: REG8(AL) = 0xff;
1.1 root 9991: break;
9992: }
9993: }
9994:
1.1.1.23 root 9995: inline void msdos_int_21h_34h()
9996: {
9997: SREG(ES) = SDA_TOP >> 4;
9998: i386_load_segment_descriptor(ES);
9999: REG16(BX) = offsetof(sda_t, indos_flag);;
10000: }
10001:
1.1 root 10002: inline void msdos_int_21h_35h()
10003: {
10004: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 10005: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
10006: i386_load_segment_descriptor(ES);
1.1 root 10007: }
10008:
10009: inline void msdos_int_21h_36h()
10010: {
10011: struct _diskfree_t df = {0};
10012:
10013: if(_getdiskfree(REG8(DL), &df) == 0) {
10014: REG16(AX) = (UINT16)df.sectors_per_cluster;
10015: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 10016: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
10017: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 10018: } else {
10019: REG16(AX) = 0xffff;
10020: }
10021: }
10022:
10023: inline void msdos_int_21h_37h()
10024: {
1.1.1.22 root 10025: static UINT8 dev_flag = 0xff;
1.1 root 10026:
10027: switch(REG8(AL)) {
10028: case 0x00:
1.1.1.22 root 10029: {
10030: process_t *process = msdos_process_info_get(current_psp);
10031: REG8(AL) = 0x00;
10032: REG8(DL) = process->switchar;
10033: }
1.1 root 10034: break;
10035: case 0x01:
1.1.1.22 root 10036: {
10037: process_t *process = msdos_process_info_get(current_psp);
10038: REG8(AL) = 0x00;
10039: process->switchar = REG8(DL);
1.1.1.23 root 10040: msdos_sda_update(current_psp);
1.1.1.22 root 10041: }
10042: break;
10043: case 0x02:
10044: REG8(DL) = dev_flag;
10045: break;
10046: case 0x03:
10047: dev_flag = REG8(DL);
10048: break;
10049: case 0xd0:
10050: case 0xd1:
10051: case 0xd2:
10052: case 0xd3:
10053: case 0xd4:
10054: case 0xd5:
10055: case 0xd6:
10056: case 0xd7:
10057: case 0xdc:
10058: case 0xdd:
10059: case 0xde:
10060: case 0xdf:
1.1.1.48 root 10061: // DIET v1.43e
10062: // REG16(AX) = 1;
10063: REG8(AL) = 0xff;
1.1 root 10064: break;
10065: default:
1.1.1.22 root 10066: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 10067: // REG16(AX) = 1;
10068: REG8(AL) = 0xff;
1.1 root 10069: break;
10070: }
10071: }
10072:
1.1.1.52 root 10073: int get_country_info(country_info_t *ci, LCID locale = LOCALE_USER_DEFAULT)
1.1.1.17 root 10074: {
10075: char LCdata[80];
10076:
1.1.1.19 root 10077: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.42 root 10078: GetLocaleInfo(locale, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
1.1.1.17 root 10079: ci->currency_dec_digits = atoi(LCdata);
1.1.1.42 root 10080: GetLocaleInfo(locale, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
1.1.1.17 root 10081: ci->currency_format = *LCdata - '0';
1.1.1.42 root 10082: GetLocaleInfo(locale, LOCALE_IDATE, LCdata, sizeof(LCdata));
1.1.1.17 root 10083: ci->date_format = *LCdata - '0';
1.1.1.42 root 10084: GetLocaleInfo(locale, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
1.1.1.17 root 10085: memcpy(&ci->currency_symbol, LCdata, 4);
1.1.1.42 root 10086: GetLocaleInfo(locale, LOCALE_SDATE, LCdata, sizeof(LCdata));
1.1.1.17 root 10087: *ci->date_sep = *LCdata;
1.1.1.42 root 10088: GetLocaleInfo(locale, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
1.1.1.17 root 10089: *ci->dec_sep = *LCdata;
1.1.1.42 root 10090: GetLocaleInfo(locale, LOCALE_SLIST, LCdata, sizeof(LCdata));
1.1.1.17 root 10091: *ci->list_sep = *LCdata;
1.1.1.42 root 10092: GetLocaleInfo(locale, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
1.1.1.17 root 10093: *ci->thou_sep = *LCdata;
1.1.1.42 root 10094: GetLocaleInfo(locale, LOCALE_STIME, LCdata, sizeof(LCdata));
1.1.1.17 root 10095: *ci->time_sep = *LCdata;
1.1.1.42 root 10096: GetLocaleInfo(locale, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
1.1.1.17 root 10097: if(strchr(LCdata, 'H') != NULL) {
10098: ci->time_format = 1;
10099: }
1.1.1.49 root 10100: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffc:000a
10101: ci->case_map.w.h = DUMMY_TOP >> 4;
1.1.1.42 root 10102: GetLocaleInfo(locale, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
1.1.1.17 root 10103: return atoi(LCdata);
10104: }
10105:
1.1.1.42 root 10106: int get_country_info(country_info_t *ci, USHORT usPrimaryLanguage, USHORT usSubLanguage)
10107: {
10108: return get_country_info(ci, MAKELCID(MAKELANGID(usPrimaryLanguage, usSubLanguage), SORT_DEFAULT));
10109: }
10110:
1.1.1.43 root 10111: void set_country_info(country_info_t *ci, int size)
10112: {
10113: char LCdata[80];
10114:
10115: if(size >= 0x00 + 2) {
10116: memset(LCdata, 0, sizeof(LCdata));
10117: *LCdata = '0' + ci->date_format;
10118: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata);
10119: }
10120: if(size >= 0x02 + 5) {
10121: memset(LCdata, 0, sizeof(LCdata));
10122: memcpy(LCdata, &ci->currency_symbol, 4);
10123: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata);
10124: }
10125: if(size >= 0x07 + 2) {
10126: memset(LCdata, 0, sizeof(LCdata));
10127: *LCdata = *ci->thou_sep;
10128: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata);
10129: }
10130: if(size >= 0x09 + 2) {
10131: memset(LCdata, 0, sizeof(LCdata));
10132: *LCdata = *ci->dec_sep;
10133: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata);
10134: }
10135: if(size >= 0x0b + 2) {
10136: memset(LCdata, 0, sizeof(LCdata));
10137: *LCdata = *ci->date_sep;
10138: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata);
10139: }
10140: if(size >= 0x0d + 2) {
10141: memset(LCdata, 0, sizeof(LCdata));
10142: *LCdata = *ci->time_sep;
10143: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata);
10144: }
10145: if(size >= 0x0f + 1) {
10146: memset(LCdata, 0, sizeof(LCdata));
10147: *LCdata = '0' + ci->currency_format;
10148: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata);
10149: }
10150: if(size >= 0x10 + 1) {
10151: sprintf(LCdata, "%d", ci->currency_dec_digits);
10152: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata);
10153: }
10154: if(size >= 0x11 + 1) {
10155: // FIXME: is time format always H/h:mm:ss ???
10156: if(ci->time_format & 1) {
10157: sprintf(LCdata, "H%cmm%css", *ci->time_sep, *ci->time_sep);
10158: } else {
10159: sprintf(LCdata, "h%cmm%css", *ci->time_sep, *ci->time_sep);
10160: }
10161: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata);
10162: }
10163: if(size >= 0x12 + 4) {
10164: // 12h DWORD address of case map routine
10165: // (FAR CALL, AL = character to map to upper case [>= 80h])
10166: }
10167: if(size >= 0x16 + 2) {
10168: memset(LCdata, 0, sizeof(LCdata));
10169: *LCdata = *ci->list_sep;
10170: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata);
10171: }
10172: }
10173:
1.1.1.42 root 10174: #ifndef SUBLANG_SWAHILI
10175: #define SUBLANG_SWAHILI 0x01
10176: #endif
10177: #ifndef SUBLANG_TSWANA_BOTSWANA
10178: #define SUBLANG_TSWANA_BOTSWANA 0x02
10179: #endif
10180: #ifndef SUBLANG_LITHUANIAN_LITHUANIA
10181: #define SUBLANG_LITHUANIAN_LITHUANIA 0x01
10182: #endif
10183: #ifndef LANG_BANGLA
10184: #define LANG_BANGLA 0x45
10185: #endif
10186: #ifndef SUBLANG_BANGLA_BANGLADESH
10187: #define SUBLANG_BANGLA_BANGLADESH 0x02
10188: #endif
10189:
10190: static const struct {
10191: int code;
10192: USHORT usPrimaryLanguage;
10193: USHORT usSubLanguage;
10194: } country_table[] = {
10195: {0x001, LANG_ENGLISH, SUBLANG_ENGLISH_US}, // United States
10196: {0x002, LANG_FRENCH, SUBLANG_FRENCH_CANADIAN}, // Canadian-French
10197: {0x004, LANG_ENGLISH, SUBLANG_ENGLISH_CAN}, // Canada (English)
10198: {0x007, LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA}, // Russia
10199: {0x014, LANG_ARABIC, SUBLANG_ARABIC_EGYPT}, // Egypt
10200: {0x01B, LANG_ZULU, SUBLANG_ZULU_SOUTH_AFRICA}, // South Africa
10201: // {0x01B, LANG_XHOSA, SUBLANG_XHOSA_SOUTH_AFRICA}, // South Africa
10202: // {0x01B, LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA}, // South Africa
10203: // {0x01B, LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA}, // South Africa
10204: // {0x01B, LANG_SOTHO, SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA}, // South Africa
10205: // {0x01B, LANG_TSWANA, SUBLANG_TSWANA_SOUTH_AFRICA}, // South Africa
10206: {0x01E, LANG_GREEK, SUBLANG_GREEK_GREECE}, // Greece
10207: {0x01F, LANG_DUTCH, SUBLANG_DUTCH}, // Netherlands
10208: // {0x01F, LANG_FRISIAN, SUBLANG_FRISIAN_NETHERLANDS}, // Netherlands
10209: {0x020, LANG_DUTCH, SUBLANG_DUTCH_BELGIAN}, // Belgium
10210: // {0x020, LANG_FRENCH, SUBLANG_FRENCH_BELGIAN}, // Belgium
10211: {0x021, LANG_FRENCH, SUBLANG_FRENCH}, // France
10212: {0x022, LANG_SPANISH, SUBLANG_SPANISH}, // Spain
10213: {0x023, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria???
10214: {0x024, LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY}, // Hungary (not supported by DR DOS 5.0)
10215: {0x027, LANG_ITALIAN, SUBLANG_ITALIAN}, // Italy / San Marino / Vatican City
10216: {0x028, LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA}, // Romania
10217: {0x029, LANG_GERMAN, SUBLANG_GERMAN_SWISS}, // Switzerland / Liechtenstein
10218: // {0x029, LANG_FRENCH, SUBLANG_FRENCH_SWISS}, // Switzerland / Liechtenstein
10219: // {0x029, LANG_ITALIAN, SUBLANG_ITALIAN_SWISS}, // Switzerland / Liechtenstein
10220: {0x02A, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0)
10221: {0x02B, LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN}, // Austria (DR DOS 5.0)
10222: {0x02C, LANG_ENGLISH, SUBLANG_ENGLISH_UK}, // United Kingdom
10223: {0x02D, LANG_DANISH, SUBLANG_DANISH_DENMARK}, // Denmark
10224: {0x02E, LANG_SWEDISH, SUBLANG_SWEDISH}, // Sweden
10225: // {0x02E, LANG_SAMI, SUBLANG_SAMI_NORTHERN_SWEDEN}, // Sweden
10226: // {0x02E, LANG_SAMI, SUBLANG_SAMI_LULE_SWEDEN}, // Sweden
10227: // {0x02E, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_SWEDEN}, // Sweden
10228: {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL}, // Norway
10229: // {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK}, // Norway
10230: // {0x02F, LANG_SAMI, SUBLANG_SAMI_NORTHERN_NORWAY}, // Norway
10231: // {0x02F, LANG_SAMI, SUBLANG_SAMI_LULE_NORWAY}, // Norway
10232: // {0x02F, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_NORWAY}, // Norway
10233: {0x030, LANG_POLISH, SUBLANG_POLISH_POLAND}, // Poland (not supported by DR DOS 5.0)
10234: {0x031, LANG_GERMAN, SUBLANG_GERMAN}, // Germany
10235: {0x033, LANG_SPANISH, SUBLANG_SPANISH_PERU}, // Peru
10236: // {0x033, LANG_QUECHUA, SUBLANG_QUECHUA_PERU}, // Peru
10237: {0x034, LANG_SPANISH, SUBLANG_SPANISH_MEXICAN}, // Mexico
10238: {0x035, LANG_SPANISH, SUBLANG_NEUTRAL}, // Cuba
10239: {0x036, LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA}, // Argentina
10240: {0x037, LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN}, // Brazil (not supported by DR DOS 5.0)
10241: {0x038, LANG_SPANISH, SUBLANG_SPANISH_CHILE}, // Chile
10242: {0x039, LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA}, // Columbia
10243: {0x03A, LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA}, // Venezuela
10244: {0x03C, LANG_MALAY, SUBLANG_MALAY_MALAYSIA}, // Malaysia
10245: {0x03D, LANG_ENGLISH, SUBLANG_ENGLISH_AUS}, // International English / Australia
10246: {0x03E, LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA}, // Indonesia / East Timor
10247: {0x03F, LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES}, // Philippines
10248: {0x040, LANG_ENGLISH, SUBLANG_ENGLISH_NZ}, // New Zealand
10249: {0x041, LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE}, // Singapore
10250: // {0x041, LANG_ENGLISH, SUBLANG_ENGLISH_SINGAPORE}, // Singapore
10251: {0x042, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan???
10252: {0x051, LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN}, // Japan (DR DOS 5.0, MS-DOS 5.0+)
10253: {0x052, LANG_KOREAN, SUBLANG_KOREAN}, // South Korea (DR DOS 5.0)
10254: {0x054, LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM}, // Vietnam
10255: {0x056, LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED}, // China (MS-DOS 5.0+)
10256: {0x058, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (MS-DOS 5.0+)
10257: {0x05A, LANG_TURKISH, SUBLANG_TURKISH_TURKEY}, // Turkey (MS-DOS 5.0+)
10258: {0x05B, LANG_HINDI, SUBLANG_HINDI_INDIA}, // India
10259: {0x05C, LANG_URDU, SUBLANG_URDU_PAKISTAN}, // Pakistan
10260: {0x05D, LANG_PASHTO, SUBLANG_PASHTO_AFGHANISTAN}, // Afghanistan
10261: // {0x05D, LANG_DARI, SUBLANG_DARI_AFGHANISTAN}, // Afghanistan
10262: {0x05E, LANG_SINHALESE, SUBLANG_SINHALESE_SRI_LANKA}, // Sri Lanka
10263: // {0x05E, LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA}, // Sri Lanka
10264: {0x062, LANG_PERSIAN, SUBLANG_PERSIAN_IRAN}, // Iran
10265: {0x070, LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS}, // Belarus
10266: {0x0C8, LANG_THAI, SUBLANG_THAI_THAILAND}, // Thailand
10267: {0x0D4, LANG_ARABIC, SUBLANG_ARABIC_MOROCCO}, // Morocco
10268: {0x0D5, LANG_ARABIC, SUBLANG_ARABIC_ALGERIA}, // Algeria
10269: {0x0D8, LANG_ARABIC, SUBLANG_ARABIC_TUNISIA}, // Tunisia
10270: {0x0DA, LANG_ARABIC, SUBLANG_ARABIC_LIBYA}, // Libya
10271: {0x0DD, LANG_WOLOF, SUBLANG_WOLOF_SENEGAL}, // Senegal
10272: // {0x0DD, LANG_PULAR, SUBLANG_PULAR_SENEGAL}, // Senegal
10273: {0x0EA, LANG_HAUSA, SUBLANG_HAUSA_NIGERIA_LATIN}, // Nigeria
10274: // {0x0EA, LANG_YORUBA, SUBLANG_YORUBA_NIGERIA}, // Nigeria
10275: // {0x0EA, LANG_IGBO, SUBLANG_IGBO_NIGERIA}, // Nigeria
10276: {0x0FB, LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA}, // Ethiopia
10277: // {0x0FB, LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA}, // Ethiopia
10278: {0x0FE, LANG_SWAHILI, SUBLANG_SWAHILI}, // Kenya
10279: {0x107, LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE}, // Zimbabwe
10280: {0x10B, LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA}, // Botswana
10281: {0x12A, LANG_FAEROESE, SUBLANG_FAEROESE_FAROE_ISLANDS}, // Faroe Islands
10282: {0x12B, LANG_GREENLANDIC, SUBLANG_GREENLANDIC_GREENLAND}, // Greenland
10283: {0x15F, LANG_PORTUGUESE, SUBLANG_PORTUGUESE}, // Portugal
10284: {0x160, LANG_LUXEMBOURGISH, SUBLANG_LUXEMBOURGISH_LUXEMBOURG}, // Luxembourg
10285: // {0x160, LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG}, // Luxembourg
10286: // {0x160, LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG}, // Luxembourg
10287: {0x161, LANG_IRISH, SUBLANG_IRISH_IRELAND}, // Ireland
10288: // {0x161, LANG_ENGLISH, SUBLANG_ENGLISH_IRELAND}, // Ireland
10289: {0x162, LANG_ICELANDIC, SUBLANG_ICELANDIC_ICELAND}, // Iceland
10290: {0x163, LANG_ALBANIAN, SUBLANG_ALBANIAN_ALBANIA}, // Albania
10291: {0x164, LANG_MALTESE, SUBLANG_MALTESE_MALTA}, // Malta
10292: {0x166, LANG_FINNISH, SUBLANG_FINNISH_FINLAND}, // Finland
10293: // {0x166, LANG_SAMI, SUBLANG_SAMI_NORTHERN_FINLAND}, // Finland
10294: // {0x166, LANG_SAMI, SUBLANG_SAMI_SKOLT_FINLAND}, // Finland
10295: // {0x166, LANG_SAMI, SUBLANG_SAMI_INARI_FINLAND}, // Finland
10296: {0x167, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria
10297: {0x172, LANG_LITHUANIAN, SUBLANG_LITHUANIAN_LITHUANIA}, // Lithuania
10298: {0x173, LANG_LATVIAN, SUBLANG_LATVIAN_LATVIA}, // Latvia
10299: {0x174, LANG_ESTONIAN, SUBLANG_ESTONIAN_ESTONIA}, // Estonia
10300: {0x17D, LANG_SERBIAN, SUBLANG_SERBIAN_LATIN}, // Serbia / Montenegro
10301: {0x180, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia???
10302: {0x181, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia
10303: {0x182, LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA}, // Slovenia
10304: {0x183, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN}, // Bosnia-Herzegovina (Latin)
10305: {0x184, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC}, // Bosnia-Herzegovina (Cyrillic)
10306: {0x185, LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA}, // FYR Macedonia
10307: {0x1A5, LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC}, // Czech Republic
10308: {0x1A6, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Slovakia
10309: {0x1F5, LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE}, // Belize
10310: {0x1F6, LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA}, // Guatemala
10311: {0x1F7, LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR}, // El Salvador
10312: {0x1F8, LANG_SPANISH, SUBLANG_SPANISH_HONDURAS}, // Honduras
10313: {0x1F9, LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA}, // Nicraragua
10314: {0x1FA, LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA}, // Costa Rica
10315: {0x1FB, LANG_SPANISH, SUBLANG_SPANISH_PANAMA}, // Panama
10316: {0x24F, LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA}, // Bolivia
1.1.1.43 root 10317: // {0x24F, LANG_QUECHUA, SUBLANG_QUECHUA_BOLIVIA}, // Bolivia
1.1.1.42 root 10318: {0x251, LANG_SPANISH, SUBLANG_SPANISH_ECUADOR}, // Ecuador
10319: // {0x251, LANG_QUECHUA, SUBLANG_QUECHUA_ECUADOR}, // Ecuador
10320: {0x253, LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY}, // Paraguay
10321: {0x256, LANG_SPANISH, SUBLANG_SPANISH_URUGUAY}, // Uruguay
10322: {0x2A1, LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM}, // Brunei Darussalam
10323: {0x311, LANG_ARABIC, SUBLANG_NEUTRAL}, // Arabic (Middle East/Saudi Arabia/etc.)
10324: {0x324, LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE}, // Ukraine
10325: {0x352, LANG_KOREAN, SUBLANG_KOREAN}, // North Korea
10326: {0x354, LANG_CHINESE, SUBLANG_CHINESE_HONGKONG}, // Hong Kong
10327: {0x355, LANG_CHINESE, SUBLANG_CHINESE_MACAU}, // Macao
10328: {0x357, LANG_KHMER, SUBLANG_KHMER_CAMBODIA}, // Cambodia
10329: {0x370, LANG_BANGLA, SUBLANG_BANGLA_BANGLADESH}, // Bangladesh
10330: {0x376, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (DOS 6.22+)
10331: {0x3C0, LANG_DIVEHI, SUBLANG_DIVEHI_MALDIVES}, // Maldives
10332: {0x3C1, LANG_ARABIC, SUBLANG_ARABIC_LEBANON}, // Lebanon
10333: {0x3C2, LANG_ARABIC, SUBLANG_ARABIC_JORDAN}, // Jordan
10334: {0x3C3, LANG_ARABIC, SUBLANG_ARABIC_SYRIA}, // Syrian Arab Republic
10335: {0x3C4, LANG_ARABIC, SUBLANG_ARABIC_IRAQ}, // Ireq
10336: {0x3C5, LANG_ARABIC, SUBLANG_ARABIC_KUWAIT}, // Kuwait
10337: {0x3C6, LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA}, // Saudi Arabia
10338: {0x3C7, LANG_ARABIC, SUBLANG_ARABIC_YEMEN}, // Yemen
10339: {0x3C8, LANG_ARABIC, SUBLANG_ARABIC_OMAN}, // Oman
10340: {0x3CB, LANG_ARABIC, SUBLANG_ARABIC_UAE}, // United Arab Emirates
10341: {0x3CC, LANG_HEBREW, SUBLANG_HEBREW_ISRAEL}, // Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+)
10342: {0x3CD, LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN}, // Bahrain
10343: {0x3CE, LANG_ARABIC, SUBLANG_ARABIC_QATAR}, // Qatar
10344: {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA}, // Mongolia
10345: // {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_PRC}, // Mongolia
10346: {0x3D1, LANG_NEPALI, SUBLANG_NEPALI_NEPAL}, // Nepal
10347: {-1, 0, 0},
10348: };
10349:
1.1.1.14 root 10350: inline void msdos_int_21h_38h()
10351: {
10352: switch(REG8(AL)) {
10353: case 0x00:
1.1.1.19 root 10354: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 10355: break;
10356: default:
1.1.1.42 root 10357: for(int i = 0;; i++) {
10358: if(country_table[i].code == (REG8(AL) != 0xff ? REG8(AL) : REG16(BX))) {
10359: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
10360: break;
10361: } else if(country_table[i].code == -1) {
10362: // 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));
10363: // REG16(AX) = 2;
10364: // m_CF = 1;
1.1.1.48 root 10365: // get current coutry info
1.1.1.42 root 10366: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
10367: break;
10368: }
10369: }
1.1.1.14 root 10370: break;
10371: }
10372: }
10373:
1.1 root 10374: inline void msdos_int_21h_39h(int lfn)
10375: {
1.1.1.3 root 10376: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10377: REG16(AX) = errno;
1.1.1.3 root 10378: m_CF = 1;
1.1 root 10379: }
10380: }
10381:
10382: inline void msdos_int_21h_3ah(int lfn)
10383: {
1.1.1.3 root 10384: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10385: REG16(AX) = errno;
1.1.1.3 root 10386: m_CF = 1;
1.1 root 10387: }
10388: }
10389:
10390: inline void msdos_int_21h_3bh(int lfn)
10391: {
1.1.1.45 root 10392: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1.1.44 root 10393:
10394: if(_chdir(path)) {
1.1.1.17 root 10395: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 10396: m_CF = 1;
1.1.1.44 root 10397: } else {
10398: int drv = _getdrive() - 1;
10399: if(path[1] == ':') {
10400: if(path[0] >= 'A' && path[0] <= 'Z') {
10401: drv = path[0] - 'A';
10402: } else if(path[0] >= 'a' && path[0] <= 'z') {
10403: drv = path[0] - 'a';
10404: }
10405: }
10406: msdos_cds_update(drv, path);
1.1 root 10407: }
10408: }
10409:
10410: inline void msdos_int_21h_3ch()
10411: {
1.1.1.45 root 10412: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10413: int attr = GetFileAttributes(path);
1.1.1.37 root 10414: int fd = -1;
10415: int sio_port = 0;
10416: int lpt_port = 0;
1.1 root 10417:
1.1.1.45 root 10418: if(msdos_is_device_path(path)) {
10419: fd = msdos_open_device(path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
1.1 root 10420: } else {
10421: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10422: }
10423: if(fd != -1) {
10424: if(attr == -1) {
10425: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
10426: }
10427: SetFileAttributes(path, attr);
10428: REG16(AX) = fd;
1.1.1.45 root 10429: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 10430: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10431: } else {
10432: REG16(AX) = errno;
1.1.1.3 root 10433: m_CF = 1;
1.1 root 10434: }
10435: }
10436:
10437: inline void msdos_int_21h_3dh()
10438: {
1.1.1.45 root 10439: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10440: int mode = REG8(AL) & 0x03;
1.1.1.37 root 10441: int fd = -1;
10442: int sio_port = 0;
10443: int lpt_port = 0;
1.1 root 10444:
10445: if(mode < 0x03) {
1.1.1.45 root 10446: if(msdos_is_device_path(path)) {
10447: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
1.1.1.11 root 10448: } else {
1.1.1.13 root 10449: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 10450: }
1.1 root 10451: if(fd != -1) {
10452: REG16(AX) = fd;
1.1.1.45 root 10453: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 10454: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10455: } else {
10456: REG16(AX) = errno;
1.1.1.3 root 10457: m_CF = 1;
1.1 root 10458: }
10459: } else {
10460: REG16(AX) = 0x0c;
1.1.1.3 root 10461: m_CF = 1;
1.1 root 10462: }
10463: }
10464:
10465: inline void msdos_int_21h_3eh()
10466: {
10467: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10468: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10469:
1.1.1.20 root 10470: if(fd < process->max_files && file_handler[fd].valid) {
10471: _close(fd);
10472: msdos_file_handler_close(fd);
10473: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 10474: } else {
10475: REG16(AX) = 0x06;
1.1.1.3 root 10476: m_CF = 1;
1.1 root 10477: }
10478: }
10479:
1.1.1.35 root 10480: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID)
10481: {
10482: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
10483: int max = REG16(CX);
10484: int p = 0;
10485:
10486: while(max > p) {
10487: int chr = msdos_getch();
10488:
10489: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
10490: p = 0;
10491: buf[p++] = 0x0d;
10492: if(max > p) {
10493: buf[p++] = 0x0a;
10494: }
10495: msdos_putch(0x03);
10496: msdos_putch(0x0d);
10497: msdos_putch(0x0a);
10498: break;
10499: } else if(ctrl_break_pressed) {
10500: // skip this byte
10501: } else if(chr == 0x00) {
10502: // skip 2nd byte
10503: msdos_getch();
10504: } else if(chr == 0x0d) {
10505: // carriage return
10506: buf[p++] = 0x0d;
10507: if(max > p) {
10508: buf[p++] = 0x0a;
10509: }
10510: msdos_putch('\n');
10511: break;
10512: } else if(chr == 0x08) {
10513: // back space
10514: if(p > 0) {
10515: p--;
10516: if(msdos_ctrl_code_check(buf[p])) {
10517: msdos_putch(0x08);
10518: msdos_putch(0x08);
10519: msdos_putch(0x20);
10520: msdos_putch(0x20);
10521: msdos_putch(0x08);
10522: msdos_putch(0x08);
1.1.1.36 root 10523: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
10524: p--;
10525: msdos_putch(0x08);
10526: msdos_putch(0x08);
10527: msdos_putch(0x20);
10528: msdos_putch(0x20);
10529: msdos_putch(0x08);
10530: msdos_putch(0x08);
1.1.1.35 root 10531: } else {
10532: msdos_putch(0x08);
10533: msdos_putch(0x20);
10534: msdos_putch(0x08);
10535: }
10536: }
10537: } else if(chr == 0x1b) {
10538: // escape
10539: while(p > 0) {
10540: p--;
10541: if(msdos_ctrl_code_check(buf[p])) {
10542: msdos_putch(0x08);
10543: msdos_putch(0x08);
10544: msdos_putch(0x20);
10545: msdos_putch(0x20);
10546: msdos_putch(0x08);
10547: msdos_putch(0x08);
10548: } else {
10549: msdos_putch(0x08);
10550: msdos_putch(0x20);
10551: msdos_putch(0x08);
10552: }
10553: }
10554: } else {
10555: buf[p++] = chr;
10556: msdos_putch(chr);
10557: }
10558: }
10559: REG16(AX) = p;
10560:
10561: #ifdef USE_SERVICE_THREAD
10562: service_exit = true;
10563: #endif
10564: return(0);
10565: }
10566:
1.1 root 10567: inline void msdos_int_21h_3fh()
10568: {
10569: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10570: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10571:
1.1.1.20 root 10572: if(fd < process->max_files && file_handler[fd].valid) {
10573: if(file_mode[file_handler[fd].mode].in) {
10574: if(file_handler[fd].atty) {
1.1 root 10575: // BX is stdin or is redirected to stdin
1.1.1.35 root 10576: if(REG16(CX) != 0) {
10577: #ifdef USE_SERVICE_THREAD
1.1.1.51 root 10578: if(!in_service && !in_service_29h &&
10579: *(UINT16 *)(mem + 4 * 0x29 + 0) == 0x29 &&
1.1.1.50 root 10580: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) {
10581: // msdos_putch() will be used in this service
10582: // if int 29h is hooked, run this service in main thread to call int 29h
10583: start_service_loop(msdos_int_21h_3fh_thread);
10584: } else {
10585: #endif
10586: msdos_int_21h_3fh_thread(NULL);
10587: REQUEST_HARDWRE_UPDATE();
10588: #ifdef USE_SERVICE_THREAD
10589: }
1.1.1.35 root 10590: #endif
10591: } else {
10592: REG16(AX) = 0;
1.1 root 10593: }
10594: } else {
1.1.1.37 root 10595: REG16(AX) = msdos_read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10596: }
10597: } else {
10598: REG16(AX) = 0x05;
1.1.1.3 root 10599: m_CF = 1;
1.1 root 10600: }
10601: } else {
10602: REG16(AX) = 0x06;
1.1.1.3 root 10603: m_CF = 1;
1.1 root 10604: }
10605: }
10606:
10607: inline void msdos_int_21h_40h()
10608: {
10609: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10610: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10611:
1.1.1.20 root 10612: if(fd < process->max_files && file_handler[fd].valid) {
10613: if(file_mode[file_handler[fd].mode].out) {
1.1 root 10614: if(REG16(CX)) {
1.1.1.20 root 10615: if(file_handler[fd].atty) {
1.1 root 10616: // BX is stdout/stderr or is redirected to stdout
10617: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 10618: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 10619: }
10620: REG16(AX) = REG16(CX);
10621: } else {
1.1.1.20 root 10622: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10623: }
10624: } else {
1.1.1.20 root 10625: UINT32 pos = _tell(fd);
10626: _lseek(fd, 0, SEEK_END);
10627: UINT32 size = _tell(fd);
1.1.1.12 root 10628: if(pos < size) {
1.1.1.20 root 10629: _lseek(fd, pos, SEEK_SET);
10630: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 10631: } else {
10632: for(UINT32 i = size; i < pos; i++) {
10633: UINT8 tmp = 0;
1.1.1.23 root 10634: msdos_write(fd, &tmp, 1);
1.1.1.12 root 10635: }
1.1.1.20 root 10636: _lseek(fd, pos, SEEK_SET);
1.1 root 10637: }
1.1.1.23 root 10638: REG16(AX) = 0;
1.1 root 10639: }
10640: } else {
10641: REG16(AX) = 0x05;
1.1.1.3 root 10642: m_CF = 1;
1.1 root 10643: }
10644: } else {
10645: REG16(AX) = 0x06;
1.1.1.3 root 10646: m_CF = 1;
1.1 root 10647: }
10648: }
10649:
10650: inline void msdos_int_21h_41h(int lfn)
10651: {
1.1.1.3 root 10652: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10653: REG16(AX) = errno;
1.1.1.3 root 10654: m_CF = 1;
1.1 root 10655: }
10656: }
10657:
10658: inline void msdos_int_21h_42h()
10659: {
10660: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10661: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10662:
1.1.1.20 root 10663: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 10664: if(REG8(AL) < 0x03) {
1.1.1.35 root 10665: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 10666: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
10667: UINT32 pos = _tell(fd);
1.1 root 10668: REG16(AX) = pos & 0xffff;
10669: REG16(DX) = (pos >> 16);
10670: } else {
10671: REG16(AX) = 0x01;
1.1.1.3 root 10672: m_CF = 1;
1.1 root 10673: }
10674: } else {
10675: REG16(AX) = 0x06;
1.1.1.3 root 10676: m_CF = 1;
1.1 root 10677: }
10678: }
10679:
10680: inline void msdos_int_21h_43h(int lfn)
10681: {
1.1.1.45 root 10682: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 10683: int attr;
10684:
1.1.1.14 root 10685: if(!lfn && REG8(AL) > 2) {
10686: REG16(AX) = 0x01;
10687: m_CF = 1;
10688: return;
10689: }
10690: switch(REG8(lfn ? BL : AL)) {
1.1 root 10691: case 0x00:
10692: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 10693: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
10694: } else {
10695: REG16(AX) = (UINT16)GetLastError();
10696: m_CF = 1;
10697: }
10698: break;
10699: case 0x01:
10700: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
10701: REG16(AX) = (UINT16)GetLastError();
10702: m_CF = 1;
10703: }
10704: break;
10705: case 0x02:
10706: {
1.1.1.45 root 10707: DWORD compressed_size = GetCompressedFileSize(path, NULL), file_size = 0;
10708: if(compressed_size != INVALID_FILE_SIZE) {
10709: if(compressed_size != 0) {
10710: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10711: if(hFile != INVALID_HANDLE_VALUE) {
10712: file_size = GetFileSize(hFile, NULL);
10713: CloseHandle(hFile);
10714: }
10715: if(compressed_size == file_size) {
10716: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
10717: // this isn't correct if the file is in the NTFS MFT
10718: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
10719: compressed_size = ((compressed_size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
10720: }
1.1.1.14 root 10721: }
10722: }
1.1.1.45 root 10723: REG16(AX) = LOWORD(compressed_size);
10724: REG16(DX) = HIWORD(compressed_size);
1.1.1.14 root 10725: } else {
10726: REG16(AX) = (UINT16)GetLastError();
10727: m_CF = 1;
1.1 root 10728: }
1.1.1.14 root 10729: }
10730: break;
10731: case 0x03:
10732: case 0x05:
10733: case 0x07:
1.1.1.48 root 10734: if(lfn) {
1.1.1.14 root 10735: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10736: if(hFile != INVALID_HANDLE_VALUE) {
10737: FILETIME local, time;
10738: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
10739: if(REG8(BL) == 7) {
10740: ULARGE_INTEGER hund;
10741: hund.LowPart = local.dwLowDateTime;
10742: hund.HighPart = local.dwHighDateTime;
10743: hund.QuadPart += REG16(SI) * 100000;
10744: local.dwLowDateTime = hund.LowPart;
10745: local.dwHighDateTime = hund.HighPart;
10746: }
10747: LocalFileTimeToFileTime(&local, &time);
10748: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
10749: REG8(BL) == 0x05 ? &time : NULL,
10750: REG8(BL) == 0x03 ? &time : NULL)) {
10751: REG16(AX) = (UINT16)GetLastError();
10752: m_CF = 1;
10753: }
10754: CloseHandle(hFile);
10755: } else {
10756: REG16(AX) = (UINT16)GetLastError();
10757: m_CF = 1;
1.1 root 10758: }
1.1.1.48 root 10759: } else {
10760: // 214303 DR DOS 3.41+ internal - Set Access Rights And Password
10761: // 214305 DR DOS 5.0-6.0 internal - Set Extended File Attributes
10762: // 214307 DR DOS 6.0 - Set File Owner
10763: // 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));
10764: REG16(AX) = 0x01;
10765: m_CF = 1;
1.1.1.14 root 10766: }
10767: break;
10768: case 0x04:
10769: case 0x06:
10770: case 0x08:
1.1.1.48 root 10771: if(lfn) {
1.1.1.14 root 10772: WIN32_FILE_ATTRIBUTE_DATA fad;
10773: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
10774: FILETIME *time, local;
10775: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
10776: 0x06 ? &fad.ftLastAccessTime :
10777: &fad.ftCreationTime;
10778: FileTimeToLocalFileTime(time, &local);
10779: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
10780: if(REG8(BL) == 0x08) {
10781: ULARGE_INTEGER hund;
10782: hund.LowPart = local.dwLowDateTime;
10783: hund.HighPart = local.dwHighDateTime;
10784: hund.QuadPart /= 100000;
10785: REG16(SI) = (UINT16)(hund.QuadPart % 200);
10786: }
10787: } else {
10788: REG16(AX) = (UINT16)GetLastError();
10789: m_CF = 1;
1.1 root 10790: }
1.1.1.48 root 10791: } else {
10792: // 214304 DR DOS 5.0-6.0 internal - Get Encrypted Password
10793: // 214306 DR DOS 6.0 - Get File Owner
10794: // 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));
10795: REG16(AX) = 0x01;
10796: m_CF = 1;
1.1.1.14 root 10797: }
10798: break;
1.1.1.43 root 10799: case 0xff:
1.1.1.48 root 10800: if(!lfn && REG16(BP) == 0x5053) {
1.1.1.43 root 10801: if(REG8(CL) == 0x39) {
10802: msdos_int_21h_39h(1);
10803: break;
10804: } else if(REG8(CL) == 0x56) {
10805: msdos_int_21h_56h(1);
10806: break;
10807: }
10808: }
1.1.1.14 root 10809: default:
1.1.1.22 root 10810: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 10811: REG16(AX) = lfn ? 0x7100 : 0x01;
1.1.1.14 root 10812: m_CF = 1;
10813: break;
10814: }
10815: }
10816:
10817: inline void msdos_int_21h_44h()
10818: {
1.1.1.22 root 10819: static UINT16 iteration_count = 0;
10820:
1.1.1.44 root 10821: process_t *process;
10822: int fd, drv;
1.1.1.14 root 10823:
10824: switch(REG8(AL)) {
10825: case 0x00:
10826: case 0x01:
10827: case 0x02:
10828: case 0x03:
10829: case 0x04:
10830: case 0x05:
10831: case 0x06:
10832: case 0x07:
1.1.1.44 root 10833: process = msdos_process_info_get(current_psp);
10834: fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1.1.20 root 10835: if(fd >= process->max_files || !file_handler[fd].valid) {
10836: REG16(AX) = 0x06;
10837: m_CF = 1;
10838: return;
1.1.1.14 root 10839: }
10840: break;
10841: case 0x08:
10842: case 0x09:
1.1.1.44 root 10843: drv = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
10844: if(!msdos_is_valid_drive(drv)) {
10845: // invalid drive
1.1.1.14 root 10846: REG16(AX) = 0x0f;
10847: m_CF = 1;
10848: return;
1.1 root 10849: }
10850: break;
10851: }
10852: switch(REG8(AL)) {
1.1.1.48 root 10853: case 0x00: // Get Device Information
1.1.1.20 root 10854: REG16(DX) = file_handler[fd].info;
1.1 root 10855: break;
1.1.1.48 root 10856: case 0x01: // Set Device Information
1.1.1.45 root 10857: if(REG8(DH) != 0) {
10858: // REG16(AX) = 0x0d; // data invalid
10859: // m_CF = 1;
10860: file_handler[fd].info = REG16(DX);
10861: } else {
10862: file_handler[fd].info &= 0xff00;
10863: file_handler[fd].info |= REG8(DL);
10864: }
1.1 root 10865: break;
1.1.1.48 root 10866: case 0x02: // Read From Character Device Control Channel
1.1.1.45 root 10867: if(strstr(file_handler[fd].path, "EMMXXXX0") != NULL && support_ems) {
10868: // from DOSBox
10869: switch(*(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX))) {
10870: case 0x00:
10871: if(REG16(CX) >= 6) {
10872: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0023;
10873: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0000;
10874: REG16(AX) = 6; // number of bytes actually read
10875: } else {
10876: REG16(AX) = 0x0d; // data invalid
10877: m_CF = 1;
10878: }
10879: break;
10880: case 0x01:
10881: if(REG16(CX) >= 6) {
10882: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x000) = 0x0004; // flags
10883: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x002) = 0x019d; // size of this structure
10884: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x004) = 0x0001; // version 1.0
10885: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x006) = 0x00000000; // reserved
10886: for(int addr = 0, ofs = 0x00a; addr < 0x100000; addr += 0x4000, ofs += 6) {
10887: if(addr >= EMS_TOP && addr < EMS_TOP + EMS_SIZE) {
10888: int page = (addr - EMS_TOP) / 0x4000;
10889: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x03; // frame type: EMS frame in 64k page
10890: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE
10891: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0x7fff; // no logical page number
10892: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = page; // physical EMS page number
10893: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0x00; // flags: EMS frame
10894: } else {
10895: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x00; // frame type: NONE
10896: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE
10897: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0xffff; // non-EMS frame
10898: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = 0xff; // EMS page number (NONE)
10899: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0xaa; // flags: direct mapping
10900: }
10901: }
10902: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18a) = 0x74; // ??
10903: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18b) = 0x00; // no UMB descriptors following
10904: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18c) = 0x01; // 1 EMS handle info record
10905: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x17d) = 0x0000; // system handle
10906: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x18f) = 0x00000000; // handle name
10907: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x193) = 0x00000000; // handle name
10908: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x197) = 0x0001; // system handle
10909: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x199) = 0x00110000; // physical address
10910:
10911: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0018;
10912: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = XMS_TOP >> 4;;
10913: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4) = 0x0001; // version 1.0
10914: REG16(AX) = 6; // number of bytes actually read
10915: } else {
10916: REG16(AX) = 0x0d; // data invalid
10917: m_CF = 1;
10918: }
10919: break;
10920: case 0x02:
10921: if(REG16(CX) >= 2) {
10922: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x40; // EMS 4.0
10923: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 1) = 0x00;
10924: REG16(AX) = 2; // number of bytes actually read
10925: } else {
10926: REG16(AX) = 0x0d; // data invalid
10927: m_CF = 1;
10928: }
10929: break;
10930: case 0x03:
10931: if(REG16(CX) >= 4) {
10932: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = MAX_EMS_PAGES * 16; // max size (kb)
10933: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0080; // min size (kb)
10934: REG16(AX) = 4; // number of bytes actually read
10935: } else {
10936: REG16(AX) = 0x0d; // data invalid
10937: m_CF = 1;
10938: }
10939: break;
10940: default:
10941: REG16(AX) = 0x01; // function number invalid
10942: m_CF = 1;
10943: }
10944: } else if(strstr(file_handler[fd].path, "CONFIG$") != NULL) {
10945: if(REG16(CX) >= 5) {
10946: memset(mem + SREG_BASE(DS) + REG16(DX), 0, 5);
10947: REG16(AX) = 5; // number of bytes actually read
10948: } else {
10949: REG16(AX) = 0x0d; // data invalid
10950: m_CF = 1;
10951: }
10952: } else {
10953: // memset(mem + SREG_BASE(DS) + REG16(DX), 0, REG16(CX));
10954: // REG16(AX) = REG16(CX);
10955: REG16(AX) = 0x05; // access denied
10956: m_CF = 1;
10957: }
10958: break;
1.1.1.48 root 10959: case 0x03: // Write To Character Device Control Channel
1.1.1.45 root 10960: // REG16(AX) = 0x05;
10961: // m_CF = 1;
10962: REG16(AX) = 0x00; // success
10963: break;
1.1.1.48 root 10964: case 0x04: // Read From Block Device Control Channel
10965: case 0x05: // Write To Block Device Control Channel
1.1 root 10966: REG16(AX) = 0x05;
1.1.1.3 root 10967: m_CF = 1;
1.1 root 10968: break;
1.1.1.48 root 10969: case 0x06: // Get Input Status
1.1.1.20 root 10970: if(file_mode[file_handler[fd].mode].in) {
10971: if(file_handler[fd].atty) {
1.1.1.14 root 10972: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 10973: } else {
1.1.1.20 root 10974: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 10975: }
1.1.1.14 root 10976: } else {
10977: REG8(AL) = 0x00;
1.1 root 10978: }
10979: break;
1.1.1.48 root 10980: case 0x07: // Get Output Status
1.1.1.20 root 10981: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 10982: REG8(AL) = 0xff;
10983: } else {
10984: REG8(AL) = 0x00;
1.1 root 10985: }
10986: break;
1.1.1.48 root 10987: case 0x08: // Check If Block Device Removable
1.1.1.44 root 10988: if(msdos_is_removable_drive(drv) || msdos_is_cdrom_drive(drv)) {
1.1.1.14 root 10989: // removable drive
10990: REG16(AX) = 0x00;
1.1 root 10991: } else {
1.1.1.14 root 10992: // fixed drive
10993: REG16(AX) = 0x01;
1.1 root 10994: }
10995: break;
1.1.1.48 root 10996: case 0x09: // Check If Block Device Remote
1.1.1.44 root 10997: if(msdos_is_remote_drive(drv)) {
1.1.1.14 root 10998: // remote drive
10999: REG16(DX) = 0x1000;
1.1.1.44 root 11000: } else if(msdos_is_subst_drive(drv)) {
11001: // subst drive
11002: REG16(DX) = 0x8000;
1.1 root 11003: } else {
1.1.1.14 root 11004: // local drive
1.1.1.44 root 11005: REG16(DX) = 0x0000;
1.1 root 11006: }
11007: break;
1.1.1.48 root 11008: case 0x0a: // Check If Handle Is Remote
1.1.1.45 root 11009: if(!(file_handler[fd].info & 0x8000) && msdos_is_remote_drive(msdos_drive_number(file_handler[fd].path))) {
11010: REG16(DX) = 0x8000;
11011: } else {
11012: REG16(DX) = 0x0000;
11013: }
1.1.1.21 root 11014: break;
1.1.1.48 root 11015: case 0x0b: // Set Sharing Retry Count
1.1 root 11016: break;
1.1.1.48 root 11017: case 0x0c: // Generic Character Device Request
1.1.1.22 root 11018: if(REG8(CL) == 0x45) {
11019: // set iteration (retry) count
11020: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
11021: } else if(REG8(CL) == 0x4a) {
11022: // select code page
11023: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
11024: msdos_nls_tables_update();
1.1.1.44 root 11025: } else if(REG8(CL) == 0x4c) {
11026: // start code-page preparation
11027: int ids[3] = {437, 0, 0}; // 437: US English
11028: int count = 1, offset = 0;
11029: if(active_code_page != 437) {
11030: ids[count++] = active_code_page;
11031: }
11032: if(system_code_page != 437 && system_code_page != active_code_page) {
11033: ids[count++] = system_code_page;
11034: }
11035: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 0;
11036: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 + 2 * count;
11037: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
11038: for(int i = 0; i < count; i++) {
11039: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
11040: }
11041: } else if(REG8(CL) == 0x4d) {
11042: // end code-page preparation
11043: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2;
11044: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
1.1.1.50 root 11045: } else if(REG8(CL) == 0x5f) {
11046: // set display information
11047: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) >= 14) {
11048: int cur_width = *(UINT16 *)(mem + 0x44a) + 0;
11049: int cur_height = *(UINT8 *)(mem + 0x484) + 1;
11050: int new_width = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // character columns
11051: int new_height = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10); // character rows
11052:
11053: if(cur_width != new_width || cur_height != new_height) {
11054: pcbios_set_console_size(new_width, new_height, true);
11055: }
11056: }
1.1.1.22 root 11057: } else if(REG8(CL) == 0x65) {
11058: // get iteration (retry) count
11059: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
11060: } else if(REG8(CL) == 0x6a) {
11061: // query selected code page
11062: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
11063: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
11064:
11065: CPINFO info;
11066: GetCPInfo(active_code_page, &info);
11067:
11068: if(info.MaxCharSize != 1) {
11069: for(int i = 0;; i++) {
11070: UINT8 lo = info.LeadByte[2 * i + 0];
11071: UINT8 hi = info.LeadByte[2 * i + 1];
11072:
11073: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
11074: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
11075: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
11076:
11077: if(lo == 0 && hi == 0) {
11078: break;
11079: }
11080: }
11081: }
1.1.1.44 root 11082: } else if(REG8(CL) == 0x6b) {
11083: // query prepare list
11084: int ids[3] = {437, 0, 0}; // 437: US English
11085: int count = 1, offset = 0;
11086: if(active_code_page != 437) {
11087: ids[count++] = active_code_page;
11088: }
11089: if(system_code_page != 437 && system_code_page != active_code_page) {
11090: ids[count++] = system_code_page;
11091: }
11092: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 * (2 + 2 * count);
11093: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
11094: for(int i = 0; i < count; i++) {
11095: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
11096: }
11097: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
11098: for(int i = 0; i < count; i++) {
11099: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
11100: }
1.1.1.22 root 11101: } else if(REG8(CL) == 0x7f) {
1.1.1.44 root 11102: // get display information
1.1.1.50 root 11103: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0; // level (0 for DOS 4.x-6.0)
11104: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0; // reserved (0)
11105: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14; // length of following data (14)
11106: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1; // bit 0 set for blink, clear for intensity
11107: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1; // mode type (1=text, 2=graphics)
11108: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0; // reserved (0)
11109: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4; // 4 bits per pixel
11110: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a) + 0); // pixel columns
11111: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1); // pixel rows
11112: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a) + 0; // character columns
11113: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1; // character rows
1.1.1.22 root 11114: } else {
11115: 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));
11116: REG16(AX) = 0x01; // invalid function
11117: m_CF = 1;
11118: }
11119: break;
1.1.1.48 root 11120: case 0x0d: // Generic Block Device Request
1.1.1.22 root 11121: if(REG8(CL) == 0x40) {
11122: // set device parameters
1.1.1.48 root 11123: // } else if(REG8(CL) == 0x41) {
11124: // // write logical device track
11125: // } else if(REG8(CL) == 0x42) {
11126: // // format and verify logical device track
1.1.1.22 root 11127: } else if(REG8(CL) == 0x46) {
11128: // set volume serial number
1.1.1.48 root 11129: } else if(REG8(CL) == 0x47) {
11130: // set access flag
11131: // } else if(REG8(CL) == 0x48) {
11132: // // set media lock state
11133: // } else if(REG8(CL) == 0x49) {
11134: // // eject media in drive
1.1.1.22 root 11135: } else if(REG8(CL) == 0x4a) {
11136: // lock logical volume
11137: } else if(REG8(CL) == 0x4b) {
11138: // lock physical volume
11139: } else if(REG8(CL) == 0x60) {
11140: // get device parameters
1.1.1.42 root 11141: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
1.1.1.22 root 11142:
1.1.1.42 root 11143: if(pcbios_update_drive_param(drive_num, 1)) {
11144: drive_param_t *drive_param = &drive_params[drive_num];
11145: DISK_GEOMETRY *geo = &drive_param->geometry;
11146:
11147: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
11148: switch(geo->MediaType) {
11149: case F5_360_512:
11150: case F5_320_512:
11151: case F5_320_1024:
11152: case F5_180_512:
11153: case F5_160_512:
11154: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
11155: break;
11156: case F5_1Pt2_512:
11157: case F3_1Pt2_512:
11158: case F3_1Pt23_1024:
11159: case F5_1Pt23_1024:
11160: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
11161: break;
11162: case F3_720_512:
11163: case F3_640_512:
11164: case F5_640_512:
11165: case F5_720_512:
11166: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
11167: break;
11168: case F8_256_128:
11169: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
11170: break;
11171: case FixedMedia:
11172: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
11173: break;
11174: case F3_1Pt44_512:
11175: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
11176: break;
11177: case F3_2Pt88_512:
11178: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
11179: break;
11180: default:
11181: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
11182: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
11183: break;
1.1.1.22 root 11184: }
1.1.1.42 root 11185: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo->MediaType == FixedMedia) ? 0x01 : 0x00;
11186: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo->Cylinders.QuadPart > 0xffff) ? 0xffff : geo->Cylinders.QuadPart;
11187: switch(geo->MediaType) {
11188: case F5_360_512:
11189: case F5_320_512:
11190: case F5_320_1024:
11191: case F5_180_512:
11192: case F5_160_512:
11193: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
11194: break;
11195: default:
11196: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
11197: break;
11198: }
11199: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo->BytesPerSector;
11200: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo->SectorsPerTrack * geo->TracksPerCylinder;
11201: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
11202: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
11203: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
11204: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
11205: switch(geo->MediaType) {
11206: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
11207: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
11208: break;
11209: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
11210: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
11211: break;
11212: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
11213: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
11214: break;
11215: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
11216: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
11217: break;
11218: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
11219: case F3_1Pt2_512:
11220: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
11221: case F5_720_512:
11222: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
11223: break;
11224: case FixedMedia: // hard disk
11225: case RemovableMedia:
11226: case Unknown:
11227: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
11228: break;
11229: default:
11230: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
11231: break;
11232: }
11233: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo->SectorsPerTrack;
11234: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
11235: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
11236: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo->TracksPerCylinder * geo->Cylinders.QuadPart;
11237: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo->Cylinders.QuadPart;
11238: // 21h BYTE device type
11239: // 22h WORD device attributes (removable or not, etc)
1.1.1.22 root 11240: } else {
11241: REG16(AX) = 0x0f; // invalid drive
11242: m_CF = 1;
11243: }
1.1.1.48 root 11244: // } else if(REG8(CL) == 0x61) {
11245: // // read logical device track
11246: // } else if(REG8(CL) == 0x62) {
11247: // // verify logical device track
1.1.1.22 root 11248: } else if(REG8(CL) == 0x66) {
11249: // get volume serial number
11250: char path[] = "A:\\";
11251: char volume_label[MAX_PATH];
11252: DWORD serial_number = 0;
11253: char file_system[MAX_PATH];
11254:
11255: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
11256:
11257: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
11258: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
11259: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
11260: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
11261: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
11262: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
11263: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
11264: } else {
11265: REG16(AX) = 0x0f; // invalid drive
11266: m_CF = 1;
11267: }
11268: } else if(REG8(CL) == 0x67) {
11269: // get access flag
11270: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
11271: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
11272: } else if(REG8(CL) == 0x68) {
11273: // sense media type
1.1.1.42 root 11274: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
1.1.1.22 root 11275:
1.1.1.42 root 11276: if(pcbios_update_drive_param(drive_num, 1)) {
11277: drive_param_t *drive_param = &drive_params[drive_num];
11278: DISK_GEOMETRY *geo = &drive_param->geometry;
11279:
11280: switch(geo->MediaType) {
11281: case F3_720_512:
11282: case F5_720_512:
11283: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
11284: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
11285: break;
11286: case F3_1Pt44_512:
11287: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
11288: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
11289: break;
11290: case F3_2Pt88_512:
11291: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
11292: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
11293: break;
11294: default:
11295: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
11296: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
11297: break;
1.1.1.22 root 11298: }
11299: } else {
11300: REG16(AX) = 0x0f; // invalid drive
11301: m_CF = 1;
11302: }
11303: } else if(REG8(CL) == 0x6a) {
11304: // unlock logical volume
11305: } else if(REG8(CL) == 0x6b) {
11306: // unlock physical volume
1.1.1.48 root 11307: // } else if(REG8(CL) == 0x6c) {
11308: // // get lock flag
11309: // } else if(REG8(CL) == 0x6d) {
11310: // // enumerate open files
11311: // } else if(REG8(CL) == 0x6e) {
11312: // // find swap file
11313: // } else if(REG8(CL) == 0x6f) {
11314: // // get drive map information
11315: // } else if(REG8(CL) == 0x70) {
11316: // // get current lock state
11317: // } else if(REG8(CL) == 0x71) {
11318: // // get first cluster
1.1.1.22 root 11319: } else {
11320: 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));
11321: REG16(AX) = 0x01; // invalid function
11322: m_CF = 1;
11323: }
11324: break;
1.1.1.48 root 11325: case 0x0e: // Get Lgical Drive Map
1.1.1.44 root 11326: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
11327: REG16(AX) = 0x0f; // invalid drive
11328: m_CF = 1;
11329: } else {
11330: REG8(AL) = 0;
1.1.1.22 root 11331: }
11332: break;
1.1.1.48 root 11333: case 0x0f: // Set Logical Drive Map
1.1.1.44 root 11334: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
11335: REG16(AX) = 0x0f; // invalid drive
11336: m_CF = 1;
1.1.1.22 root 11337: }
11338: break;
1.1.1.48 root 11339: case 0x10: // Query Generic IOCTRL Capability (Handle)
1.1.1.22 root 11340: switch(REG8(CL)) {
11341: case 0x45:
11342: case 0x4a:
1.1.1.48 root 11343: case 0x4c:
11344: case 0x4d:
1.1.1.22 root 11345: case 0x65:
11346: case 0x6a:
1.1.1.48 root 11347: case 0x6b:
1.1.1.22 root 11348: case 0x7f:
11349: REG16(AX) = 0x0000; // supported
11350: break;
11351: default:
11352: REG8(AL) = 0x01; // ioctl capability not available
11353: m_CF = 1;
11354: break;
11355: }
11356: break;
1.1.1.48 root 11357: case 0x11: // Query Generic IOCTRL Capability (Drive)
1.1.1.22 root 11358: switch(REG8(CL)) {
11359: case 0x40:
11360: case 0x46:
11361: case 0x4a:
11362: case 0x4b:
11363: case 0x60:
11364: case 0x66:
11365: case 0x67:
11366: case 0x68:
11367: case 0x6a:
11368: case 0x6b:
1.1.1.48 root 11369: if(REG8(CH) == 0x00 || REG8(CH) == 0x01 || REG8(CH) == 0x03 || REG8(CH) == 0x05) {
11370: // CH = 00h Unknown
11371: // CH = 01h COMn:
11372: // CH = 03h CON
11373: // CH = 05h LPTn:
11374: REG16(AX) = 0x0000; // supported
11375: break;
11376: }
1.1.1.22 root 11377: default:
11378: REG8(AL) = 0x01; // ioctl capability not available
11379: m_CF = 1;
11380: break;
11381: }
11382: break;
1.1.1.48 root 11383: case 0x12: // DR DOS 5.0-6.0 - Determine DOS Type
11384: case 0x14: // DR DOS 5.0-6.0 - Set Global Password
11385: case 0x16: // DR DOS 5.0-6.0 - History Buffer, Share, And Hiload Control
11386: case 0x51: // Concurrent DOS v3.2+ - Installation Check
11387: case 0x52: // DR DOS 3.41+ - Determine DOS tTpe/Get DR DOS Version
11388: case 0x54: // DR DOS 3.41+ - Set Global Password
11389: case 0x56: // DR DOS 5.0+ - History Buffer Control
11390: case 0x57: // DR DOS 5.0-6.0 - Share/Hiload Control
11391: case 0x58: // DR DOS 5.0+ internal - Get Pointer To Internal Variable Table
11392: case 0x59: // DR Multiuser DOS 5.0 - API
11393: REG16(AX) = 0x01; // this is not DR-DOS
1.1.1.22 root 11394: m_CF = 1;
11395: break;
1.1 root 11396: default:
1.1.1.22 root 11397: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11398: REG16(AX) = 0x01;
1.1.1.3 root 11399: m_CF = 1;
1.1 root 11400: break;
11401: }
11402: }
11403:
11404: inline void msdos_int_21h_45h()
11405: {
11406: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11407: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 11408:
1.1.1.20 root 11409: if(fd < process->max_files && file_handler[fd].valid) {
11410: int dup_fd = _dup(fd);
11411: if(dup_fd != -1) {
11412: REG16(AX) = dup_fd;
11413: msdos_file_handler_dup(dup_fd, fd, current_psp);
11414: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
11415: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 11416: } else {
11417: REG16(AX) = errno;
1.1.1.3 root 11418: m_CF = 1;
1.1 root 11419: }
11420: } else {
11421: REG16(AX) = 0x06;
1.1.1.3 root 11422: m_CF = 1;
1.1 root 11423: }
11424: }
11425:
11426: inline void msdos_int_21h_46h()
11427: {
11428: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11429: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11430: int dup_fd = REG16(CX);
11431: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 11432:
1.1.1.20 root 11433: if(REG16(BX) == REG16(CX)) {
11434: REG16(AX) = 0x06;
11435: m_CF = 1;
11436: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
11437: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
11438: _close(tmp_fd);
11439: msdos_file_handler_close(tmp_fd);
11440: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
11441: }
11442: if(_dup2(fd, dup_fd) != -1) {
11443: msdos_file_handler_dup(dup_fd, fd, current_psp);
11444: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
11445: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 11446: } else {
11447: REG16(AX) = errno;
1.1.1.3 root 11448: m_CF = 1;
1.1 root 11449: }
11450: } else {
11451: REG16(AX) = 0x06;
1.1.1.3 root 11452: m_CF = 1;
1.1 root 11453: }
11454: }
11455:
11456: inline void msdos_int_21h_47h(int lfn)
11457: {
11458: char path[MAX_PATH];
11459:
11460: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
1.1.1.45 root 11461: if(!lfn) {
11462: strcpy(path, msdos_short_path(path));
11463: }
1.1 root 11464: if(path[1] == ':') {
11465: // the returned path does not include a drive or the initial backslash
1.1.1.45 root 11466: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path + 3);
1.1 root 11467: } else {
1.1.1.45 root 11468: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path);
1.1 root 11469: }
11470: } else {
11471: REG16(AX) = errno;
1.1.1.3 root 11472: m_CF = 1;
1.1 root 11473: }
11474: }
11475:
11476: inline void msdos_int_21h_48h()
11477: {
1.1.1.19 root 11478: int seg, umb_linked;
1.1 root 11479:
1.1.1.8 root 11480: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 11481: // unlink umb not to allocate memory in umb
11482: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
11483: msdos_mem_unlink_umb();
11484: }
1.1.1.8 root 11485: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
11486: REG16(AX) = seg;
11487: } else {
11488: REG16(AX) = 0x08;
11489: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
11490: m_CF = 1;
11491: }
1.1.1.19 root 11492: if(umb_linked != 0) {
11493: msdos_mem_link_umb();
11494: }
1.1.1.8 root 11495: } else if((malloc_strategy & 0xf0) == 0x40) {
11496: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
11497: REG16(AX) = seg;
11498: } else {
11499: REG16(AX) = 0x08;
11500: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
11501: m_CF = 1;
11502: }
11503: } else if((malloc_strategy & 0xf0) == 0x80) {
11504: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
11505: REG16(AX) = seg;
11506: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
11507: REG16(AX) = seg;
11508: } else {
11509: REG16(AX) = 0x08;
11510: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
11511: m_CF = 1;
11512: }
1.1 root 11513: }
11514: }
11515:
11516: inline void msdos_int_21h_49h()
11517: {
1.1.1.14 root 11518: int mcb_seg = SREG(ES) - 1;
11519: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
11520:
11521: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11522: msdos_mem_free(SREG(ES));
11523: } else {
1.1.1.33 root 11524: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 11525: m_CF = 1;
11526: }
1.1 root 11527: }
11528:
11529: inline void msdos_int_21h_4ah()
11530: {
1.1.1.14 root 11531: int mcb_seg = SREG(ES) - 1;
11532: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 11533: int max_paragraphs;
11534:
1.1.1.14 root 11535: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11536: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
11537: REG16(AX) = 0x08;
11538: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
11539: m_CF = 1;
11540: }
11541: } else {
1.1.1.33 root 11542: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 11543: m_CF = 1;
1.1 root 11544: }
11545: }
11546:
11547: inline void msdos_int_21h_4bh()
11548: {
1.1.1.3 root 11549: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
11550: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 11551:
11552: switch(REG8(AL)) {
11553: case 0x00:
11554: case 0x01:
11555: if(msdos_process_exec(command, param, REG8(AL))) {
11556: REG16(AX) = 0x02;
1.1.1.3 root 11557: m_CF = 1;
1.1 root 11558: }
11559: break;
1.1.1.14 root 11560: case 0x03:
11561: {
11562: int fd;
11563: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
11564: REG16(AX) = 0x02;
11565: m_CF = 1;
11566: break;
11567: }
11568: int size = _read(fd, file_buffer, sizeof(file_buffer));
11569: _close(fd);
11570:
11571: UINT16 *overlay = (UINT16 *)param;
11572:
11573: // check exe header
11574: exe_header_t *header = (exe_header_t *)file_buffer;
11575: int header_size = 0;
11576: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
11577: header_size = header->header_size * 16;
11578: // relocation
11579: int start_seg = overlay[1];
11580: for(int i = 0; i < header->relocations; i++) {
11581: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
11582: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
11583: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
11584: }
11585: }
11586: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
11587: }
11588: break;
1.1.1.48 root 11589: case 0x04:
11590: // Load And Execute In Background (European MS-DOS 4.0 only)
11591: // case 0x05:
11592: // // DOS 5+ - Set Execution State
11593: case 0x80:
11594: // DR DOS v3.41 - Run Already-Loaded Kernel File
11595: case 0xf0:
11596: case 0xf1:
11597: // DIET v1.10+
1.1.1.43 root 11598: case 0xfd:
11599: case 0xfe:
11600: // unknown function called in FreeCOM
11601: REG16(AX) = 0x01;
11602: m_CF = 1;
11603: break;
1.1 root 11604: default:
1.1.1.22 root 11605: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11606: REG16(AX) = 0x01;
1.1.1.3 root 11607: m_CF = 1;
1.1 root 11608: break;
11609: }
11610: }
11611:
11612: inline void msdos_int_21h_4ch()
11613: {
11614: msdos_process_terminate(current_psp, REG8(AL), 1);
11615: }
11616:
11617: inline void msdos_int_21h_4dh()
11618: {
11619: REG16(AX) = retval;
11620: }
11621:
11622: inline void msdos_int_21h_4eh()
11623: {
11624: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 11625: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
11626: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.45 root 11627: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 11628: WIN32_FIND_DATA fd;
11629:
1.1.1.14 root 11630: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
11631: find->find_magic = FIND_MAGIC;
11632: find->dta_index = dtainfo - dtalist;
1.1 root 11633: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 11634: dtainfo->allowable_mask = REG8(CL);
11635: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 11636:
1.1.1.14 root 11637: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
11638: dtainfo->allowable_mask &= ~8;
1.1 root 11639: }
1.1.1.14 root 11640: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
11641: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 11642: !msdos_find_file_has_8dot3name(&fd)) {
11643: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11644: FindClose(dtainfo->find_handle);
11645: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11646: break;
11647: }
11648: }
11649: }
1.1.1.13 root 11650: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11651: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
11652: msdos_find_file_conv_local_time(&fd);
11653: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
11654: find->size = fd.nFileSizeLow;
1.1.1.13 root 11655: strcpy(find->name, msdos_short_name(&fd));
1.1 root 11656: REG16(AX) = 0;
1.1.1.14 root 11657: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11658: find->attrib = 8;
11659: find->size = 0;
11660: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11661: dtainfo->allowable_mask &= ~8;
1.1 root 11662: REG16(AX) = 0;
11663: } else {
11664: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 11665: m_CF = 1;
1.1 root 11666: }
11667: }
11668:
11669: inline void msdos_int_21h_4fh()
11670: {
11671: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 11672: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
11673: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 11674: WIN32_FIND_DATA fd;
11675:
1.1.1.14 root 11676: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
11677: REG16(AX) = 0x12;
11678: m_CF = 1;
11679: return;
11680: }
11681: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 11682: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
11683: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 11684: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 11685: !msdos_find_file_has_8dot3name(&fd)) {
11686: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11687: FindClose(dtainfo->find_handle);
11688: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11689: break;
11690: }
11691: }
11692: } else {
1.1.1.13 root 11693: FindClose(dtainfo->find_handle);
11694: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11695: }
11696: }
1.1.1.13 root 11697: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11698: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
11699: msdos_find_file_conv_local_time(&fd);
11700: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
11701: find->size = fd.nFileSizeLow;
1.1.1.13 root 11702: strcpy(find->name, msdos_short_name(&fd));
1.1 root 11703: REG16(AX) = 0;
1.1.1.14 root 11704: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11705: find->attrib = 8;
11706: find->size = 0;
11707: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11708: dtainfo->allowable_mask &= ~8;
1.1 root 11709: REG16(AX) = 0;
11710: } else {
11711: REG16(AX) = 0x12;
1.1.1.3 root 11712: m_CF = 1;
1.1 root 11713: }
11714: }
11715:
11716: inline void msdos_int_21h_50h()
11717: {
1.1.1.8 root 11718: if(current_psp != REG16(BX)) {
11719: process_t *process = msdos_process_info_get(current_psp);
11720: if(process != NULL) {
11721: process->psp = REG16(BX);
11722: }
11723: current_psp = REG16(BX);
1.1.1.23 root 11724: msdos_sda_update(current_psp);
1.1.1.8 root 11725: }
1.1 root 11726: }
11727:
11728: inline void msdos_int_21h_51h()
11729: {
11730: REG16(BX) = current_psp;
11731: }
11732:
11733: inline void msdos_int_21h_52h()
11734: {
1.1.1.25 root 11735: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 11736: i386_load_segment_descriptor(ES);
1.1.1.25 root 11737: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 11738: }
11739:
1.1.1.43 root 11740: inline void msdos_int_21h_53h()
11741: {
11742: dpb_t *dpb = (dpb_t *)(mem + SREG_BASE(ES) + REG16(BP));
11743: bpb_t *bpb = (bpb_t *)(mem + SREG_BASE(DS) + REG16(SI));
11744:
11745: dpb->bytes_per_sector = bpb->bytes_per_sector;
11746: dpb->highest_sector_num = bpb->sectors_per_track - 1;
11747: dpb->shift_count = 0;
11748: dpb->reserved_sectors = 0;
11749: dpb->fat_num = bpb->fat_num;
11750: dpb->root_entries = bpb->root_entries;
11751: dpb->first_data_sector = 0;
11752: if(bpb->sectors_per_cluster != 0) {
11753: dpb->highest_cluster_num = (UINT16)(((REG16(CX) == 0x4558 && bpb->total_sectors == 0) ? bpb->ext_total_sectors : bpb->total_sectors) / bpb->sectors_per_cluster + 1);
11754: } else {
11755: dpb->highest_cluster_num = 0;
11756: }
11757: dpb->sectors_per_fat = (REG16(CX) == 0x4558 && bpb->sectors_per_fat == 0) ? bpb->ext_sectors_per_fat : bpb->sectors_per_fat;
11758: dpb->first_dir_sector = 0;
11759: dpb->device_driver_header = 0;
11760: dpb->media_type = bpb->media_type;
11761: dpb->drive_accessed = 0;
11762: dpb->next_dpb_ofs = 0xffff;
11763: dpb->next_dpb_seg = 0xffff;
11764: dpb->first_free_cluster = 0;
11765: dpb->free_clusters = 0xffff;
11766: }
11767:
1.1 root 11768: inline void msdos_int_21h_54h()
11769: {
11770: process_t *process = msdos_process_info_get(current_psp);
11771:
11772: REG8(AL) = process->verify;
11773: }
11774:
11775: inline void msdos_int_21h_55h()
11776: {
11777: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
11778:
11779: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
11780: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
11781: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
11782: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
11783: psp->parent_psp = current_psp;
11784: }
11785:
11786: inline void msdos_int_21h_56h(int lfn)
11787: {
11788: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 11789: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
11790: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 11791:
11792: if(rename(src, dst)) {
11793: REG16(AX) = errno;
1.1.1.3 root 11794: m_CF = 1;
1.1 root 11795: }
11796: }
11797:
11798: inline void msdos_int_21h_57h()
11799: {
11800: FILETIME time, local;
1.1.1.14 root 11801: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 11802: HANDLE hHandle;
1.1 root 11803:
1.1.1.21 root 11804: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 11805: REG16(AX) = (UINT16)GetLastError();
11806: m_CF = 1;
11807: return;
11808: }
11809: ctime = atime = mtime = NULL;
11810:
1.1 root 11811: switch(REG8(AL)) {
11812: case 0x00:
1.1.1.6 root 11813: case 0x01:
1.1.1.14 root 11814: mtime = &time;
1.1.1.6 root 11815: break;
11816: case 0x04:
11817: case 0x05:
1.1.1.14 root 11818: atime = &time;
1.1 root 11819: break;
1.1.1.6 root 11820: case 0x06:
11821: case 0x07:
1.1.1.14 root 11822: ctime = &time;
11823: break;
11824: default:
1.1.1.22 root 11825: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 11826: REG16(AX) = 0x01;
11827: m_CF = 1;
11828: return;
11829: }
11830: if(REG8(AL) & 1) {
1.1 root 11831: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
11832: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 11833: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 11834: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11835: m_CF = 1;
1.1 root 11836: }
1.1.1.14 root 11837: } else {
1.1.1.21 root 11838: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 11839: // assume a device and use the current time
11840: GetSystemTimeAsFileTime(&time);
11841: }
11842: FileTimeToLocalFileTime(&time, &local);
11843: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 11844: }
11845: }
11846:
11847: inline void msdos_int_21h_58h()
11848: {
11849: switch(REG8(AL)) {
11850: case 0x00:
1.1.1.7 root 11851: REG16(AX) = malloc_strategy;
11852: break;
11853: case 0x01:
1.1.1.24 root 11854: // switch(REG16(BX)) {
11855: switch(REG8(BL)) {
1.1.1.7 root 11856: case 0x0000:
11857: case 0x0001:
11858: case 0x0002:
11859: case 0x0040:
11860: case 0x0041:
11861: case 0x0042:
11862: case 0x0080:
11863: case 0x0081:
11864: case 0x0082:
11865: malloc_strategy = REG16(BX);
1.1.1.23 root 11866: msdos_sda_update(current_psp);
1.1.1.7 root 11867: break;
11868: default:
1.1.1.22 root 11869: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.7 root 11870: REG16(AX) = 0x01;
11871: m_CF = 1;
11872: break;
11873: }
11874: break;
11875: case 0x02:
1.1.1.19 root 11876: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 11877: break;
11878: case 0x03:
1.1.1.24 root 11879: // switch(REG16(BX)) {
11880: switch(REG8(BL)) {
1.1.1.7 root 11881: case 0x0000:
1.1.1.19 root 11882: msdos_mem_unlink_umb();
11883: break;
1.1.1.7 root 11884: case 0x0001:
1.1.1.19 root 11885: msdos_mem_link_umb();
1.1.1.7 root 11886: break;
11887: default:
1.1.1.22 root 11888: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.7 root 11889: REG16(AX) = 0x01;
11890: m_CF = 1;
11891: break;
11892: }
1.1 root 11893: break;
11894: default:
1.1.1.22 root 11895: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11896: REG16(AX) = 0x01;
1.1.1.3 root 11897: m_CF = 1;
1.1 root 11898: break;
11899: }
11900: }
11901:
11902: inline void msdos_int_21h_59h()
11903: {
1.1.1.47 root 11904: if(REG16(BX) == 0x0000) {
11905: sda_t *sda = (sda_t *)(mem + SDA_TOP);
11906:
11907: REG16(AX) = sda->extended_error_code;
11908: REG8(BH) = sda->error_class;
11909: REG8(BL) = sda->suggested_action;
11910: REG8(CH) = sda->locus_of_last_error;
11911: // XXX: GW-BASIC 3.23 invites the registers contents of CL, DX, SI, DI, DS, and ES are not destroyed
11912: if(sda->int21h_5d0ah_called != 0) {
11913: REG8(CL) = sda->int21h_5d0ah_cl;
11914: REG16(DX) = sda->int21h_5d0ah_dx;
11915: // REG16(SI) = sda->int21h_5d0ah_si;
11916: REG16(DI) = sda->last_error_pointer.w.l;
11917: // SREG(DS) = sda->int21h_5d0ah_ds;
11918: // i386_load_segment_descriptor(DS);
11919: SREG(ES) = sda->last_error_pointer.w.h;
11920: i386_load_segment_descriptor(ES);
11921: }
11922: sda->int21h_5d0ah_called = 0;
11923: // } else if(REG16(BX) == 0x0001) {
11924: // // European MS-DOS 4.0 - Get Hard Error Information
11925: } else {
11926: 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));
11927: REG16(AX) = 0x01;
11928: m_CF = 1;
11929: }
1.1 root 11930: }
11931:
11932: inline void msdos_int_21h_5ah()
11933: {
1.1.1.3 root 11934: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 11935: int len = strlen(path);
11936: char tmp[MAX_PATH];
11937:
11938: if(GetTempFileName(path, "TMP", 0, tmp)) {
11939: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11940:
11941: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11942: REG16(AX) = fd;
11943: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11944: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11945:
11946: strcpy(path, tmp);
11947: int dx = REG16(DX) + len;
1.1.1.3 root 11948: int ds = SREG(DS);
1.1 root 11949: while(dx > 0xffff) {
11950: dx -= 0x10;
11951: ds++;
11952: }
11953: REG16(DX) = dx;
1.1.1.3 root 11954: SREG(DS) = ds;
11955: i386_load_segment_descriptor(DS);
1.1 root 11956: } else {
11957: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11958: m_CF = 1;
1.1 root 11959: }
11960: }
11961:
11962: inline void msdos_int_21h_5bh()
11963: {
1.1.1.45 root 11964: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 11965:
1.1.1.45 root 11966: // if(msdos_is_existing_file(path)) {
11967: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 11968: // already exists
11969: REG16(AX) = 0x50;
1.1.1.3 root 11970: m_CF = 1;
1.1 root 11971: } else {
11972: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11973:
11974: if(fd != -1) {
11975: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11976: REG16(AX) = fd;
11977: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11978: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11979: } else {
11980: REG16(AX) = errno;
1.1.1.3 root 11981: m_CF = 1;
1.1 root 11982: }
11983: }
11984: }
11985:
11986: inline void msdos_int_21h_5ch()
11987: {
11988: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11989: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 11990:
1.1.1.20 root 11991: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 11992: if(REG8(AL) == 0 || REG8(AL) == 1) {
1.1.1.35 root 11993: static const int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 11994: UINT32 pos = _tell(fd);
11995: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
11996: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 11997: REG16(AX) = errno;
1.1.1.3 root 11998: m_CF = 1;
1.1 root 11999: }
1.1.1.20 root 12000: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 12001:
1.1 root 12002: // some seconds may be passed in _locking()
1.1.1.35 root 12003: REQUEST_HARDWRE_UPDATE();
1.1 root 12004: } else {
12005: REG16(AX) = 0x01;
1.1.1.3 root 12006: m_CF = 1;
1.1 root 12007: }
12008: } else {
12009: REG16(AX) = 0x06;
1.1.1.3 root 12010: m_CF = 1;
1.1 root 12011: }
12012: }
12013:
1.1.1.22 root 12014: inline void msdos_int_21h_5dh()
12015: {
12016: switch(REG8(AL)) {
1.1.1.45 root 12017: case 0x00:
12018: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x12) == 0x0000) {
12019: // current system
12020: static bool reenter = false;
12021: if(!reenter) {
12022: UINT32 offset = SREG_BASE(DS) + REG16(DX);
12023: REG16(AX) = *(UINT16 *)(mem + offset + 0x00);
12024: REG16(BX) = *(UINT16 *)(mem + offset + 0x02);
12025: REG16(CX) = *(UINT16 *)(mem + offset + 0x04);
12026: REG16(DX) = *(UINT16 *)(mem + offset + 0x06);
12027: REG16(SI) = *(UINT16 *)(mem + offset + 0x08);
12028: REG16(DI) = *(UINT16 *)(mem + offset + 0x0a);
12029: SREG(DS) = *(UINT16 *)(mem + offset + 0x0c);
12030: SREG(ES) = *(UINT16 *)(mem + offset + 0x0e);
12031: i386_load_segment_descriptor(DS);
12032: i386_load_segment_descriptor(ES);
12033: reenter = true;
12034: try {
12035: msdos_syscall(0x21);
12036: } catch(...) {
12037: }
12038: reenter = false;
12039: }
12040: } else {
12041: REG16(AX) = 0x49; // network software not installed
12042: m_CF = 1;
12043: }
12044: break;
1.1.1.22 root 12045: case 0x06: // get address of dos swappable data area
1.1.1.23 root 12046: SREG(DS) = (SDA_TOP >> 4);
12047: i386_load_segment_descriptor(DS);
12048: REG16(SI) = offsetof(sda_t, crit_error_flag);
12049: REG16(CX) = 0x80;
12050: REG16(DX) = 0x1a;
12051: break;
1.1.1.45 root 12052: case 0x07: // get redirected printer mode
12053: case 0x08: // set redirected printer mode
12054: case 0x09: // flush redirected printer output
12055: REG16(AX) = 0x49; // network software not installed
12056: m_CF = 1;
12057: break;
1.1.1.43 root 12058: case 0x0a: // set extended error information
12059: {
12060: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1.1.1.47 root 12061: sda->int21h_5d0ah_called = 1;
1.1.1.43 root 12062: sda->extended_error_code = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00); // AX
1.1.1.47 root 12063: // XXX: which one is correct ???
12064: #if 1
12065: // Ralf Brown's Interrupt List and DR-DOS System and Programmer's Guide
1.1.1.43 root 12066: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BL
12067: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BH
1.1.1.47 root 12068: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CL
1.1.1.43 root 12069: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CH
1.1.1.47 root 12070: #else
12071: // PC DOS 7 Technical Update
12072: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BH
12073: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BL
12074: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CH
12075: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CL
12076: #endif
12077: sda->int21h_5d0ah_dx = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06); // DX
12078: // sda->int21h_5d0ah_si = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08); // SI
1.1.1.43 root 12079: sda->last_error_pointer.w.l = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a); // DI
1.1.1.47 root 12080: // sda->int21h_5d0ah_ds = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c); // DS
1.1.1.43 root 12081: sda->last_error_pointer.w.h = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // ES
12082: }
12083: break;
1.1.1.23 root 12084: case 0x0b: // get dos swappable data areas
1.1.1.22 root 12085: REG16(AX) = 0x01;
12086: m_CF = 1;
12087: break;
12088: default:
12089: 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));
12090: REG16(AX) = 0x01;
12091: m_CF = 1;
12092: break;
12093: }
12094: }
12095:
1.1.1.42 root 12096: inline void msdos_int_21h_5eh()
12097: {
12098: switch(REG8(AL)) {
12099: case 0x00:
12100: {
12101: char name[256] = {0};
12102: DWORD dwSize = 256;
12103:
12104: if(GetComputerName(name, &dwSize)) {
12105: char *dest = (char *)(mem + SREG_BASE(DS) + REG16(DX));
12106: for(int i = 0; i < 15; i++) {
12107: dest[i] = (i < strlen(name)) ? name[i] : ' ';
12108: }
12109: dest[15] = '\0';
12110: REG8(CH) = 0x01; // nonzero valid
12111: REG8(CL) = 0x01; // NetBIOS number for machine name ???
12112: } else {
12113: REG16(AX) = 0x01;
12114: m_CF = 1;
12115: }
12116: }
12117: break;
12118: default:
1.1.1.45 root 12119: // 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));
12120: // REG16(AX) = 0x01;
12121: REG16(AX) = 0x49; // network software not installed
1.1.1.42 root 12122: m_CF = 1;
12123: break;
12124: }
12125: }
12126:
1.1.1.30 root 12127: inline void msdos_int_21h_5fh()
12128: {
12129: switch(REG8(AL)) {
1.1.1.42 root 12130: case 0x05:
1.1.1.44 root 12131: REG16(BP) = 0;
12132: for(int i = 0; i < 26; i++) {
12133: if(msdos_is_remote_drive(i)) {
12134: REG16(BP)++;
1.1.1.42 root 12135: }
12136: }
1.1.1.30 root 12137: case 0x02:
1.1.1.44 root 12138: for(int i = 0, index = 0; i < 26; i++) {
12139: if(msdos_is_remote_drive(i)) {
12140: if(index == REG16(BX)) {
12141: char volume[] = "A:";
1.1.1.30 root 12142: volume[0] = 'A' + i;
1.1.1.44 root 12143: DWORD dwSize = 128;
12144: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
12145: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
12146: REG8(BH) = 0x00; // valid
12147: REG8(BL) = 0x04; // disk drive
12148: REG16(CX) = 0x00; // LANtastic
12149: return;
1.1.1.30 root 12150: }
1.1.1.44 root 12151: index++;
1.1.1.30 root 12152: }
12153: }
12154: REG16(AX) = 0x12; // no more files
12155: m_CF = 1;
12156: break;
1.1.1.44 root 12157: case 0x07:
12158: if(msdos_is_valid_drive(REG8(DL))) {
12159: msdos_cds_update(REG8(DL));
12160: } else {
12161: REG16(AX) = 0x0f; // invalid drive
12162: m_CF = 1;
12163: }
12164: break;
12165: case 0x08:
12166: if(msdos_is_valid_drive(REG8(DL))) {
12167: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * REG8(DL));
12168: cds->drive_attrib = 0x0000;
12169: } else {
12170: REG16(AX) = 0x0f; // invalid drive
12171: m_CF = 1;
12172: }
12173: break;
1.1.1.30 root 12174: default:
1.1.1.45 root 12175: // 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));
12176: // REG16(AX) = 0x01;
12177: REG16(AX) = 0x49; // network software not installed
1.1.1.30 root 12178: m_CF = 1;
12179: break;
12180: }
12181: }
12182:
1.1 root 12183: inline void msdos_int_21h_60h(int lfn)
12184: {
1.1.1.45 root 12185: char full[MAX_PATH];
12186: const char *path = NULL;
1.1.1.14 root 12187:
1.1 root 12188: if(lfn) {
1.1.1.14 root 12189: char *name;
12190: *full = '\0';
1.1.1.3 root 12191: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 12192: switch(REG8(CL)) {
12193: case 1:
12194: GetShortPathName(full, full, MAX_PATH);
12195: my_strupr(full);
12196: break;
12197: case 2:
12198: GetLongPathName(full, full, MAX_PATH);
12199: break;
12200: }
12201: path = full;
12202: } else {
12203: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
12204: }
12205: if(*path != '\0') {
12206: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 12207: } else {
1.1.1.14 root 12208: REG16(AX) = (UINT16)GetLastError();
12209: m_CF = 1;
1.1 root 12210: }
12211: }
12212:
12213: inline void msdos_int_21h_61h()
12214: {
12215: REG8(AL) = 0;
12216: }
12217:
12218: inline void msdos_int_21h_62h()
12219: {
12220: REG16(BX) = current_psp;
12221: }
12222:
12223: inline void msdos_int_21h_63h()
12224: {
12225: switch(REG8(AL)) {
12226: case 0x00:
1.1.1.3 root 12227: SREG(DS) = (DBCS_TABLE >> 4);
12228: i386_load_segment_descriptor(DS);
1.1 root 12229: REG16(SI) = (DBCS_TABLE & 0x0f);
12230: REG8(AL) = 0x00;
12231: break;
1.1.1.22 root 12232: case 0x01: // set korean input mode
12233: case 0x02: // get korean input mode
12234: REG8(AL) = 0xff; // not supported
12235: break;
1.1 root 12236: default:
1.1.1.22 root 12237: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 12238: REG16(AX) = 0x01;
1.1.1.3 root 12239: m_CF = 1;
1.1 root 12240: break;
12241: }
12242: }
12243:
1.1.1.25 root 12244: UINT16 get_extended_country_info(UINT8 func)
1.1 root 12245: {
1.1.1.25 root 12246: switch(func) {
1.1.1.17 root 12247: case 0x01:
12248: if(REG16(CX) >= 5) {
1.1.1.19 root 12249: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 12250: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
12251: REG16(CX) = sizeof(data);
12252: ZeroMemory(data, sizeof(data));
12253: data[0] = 0x01;
12254: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 12255: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 12256: *(UINT16 *)(data + 5) = active_code_page;
12257: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 12258: // REG16(AX) = active_code_page;
1.1.1.17 root 12259: } else {
1.1.1.25 root 12260: return(0x08); // insufficient memory
1.1.1.17 root 12261: }
12262: break;
12263: case 0x02:
12264: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
12265: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
12266: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 12267: // REG16(AX) = active_code_page;
1.1.1.17 root 12268: REG16(CX) = 0x05;
12269: break;
1.1.1.23 root 12270: case 0x03:
12271: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
12272: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
12273: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 12274: // REG16(AX) = active_code_page;
1.1.1.23 root 12275: REG16(CX) = 0x05;
12276: break;
1.1.1.17 root 12277: case 0x04:
12278: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
12279: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
12280: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 12281: // REG16(AX) = active_code_page;
1.1.1.17 root 12282: REG16(CX) = 0x05;
12283: break;
12284: case 0x05:
12285: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
12286: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
12287: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 12288: // REG16(AX) = active_code_page;
1.1.1.17 root 12289: REG16(CX) = 0x05;
12290: break;
12291: case 0x06:
12292: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
12293: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
12294: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 12295: // REG16(AX) = active_code_page;
1.1.1.17 root 12296: REG16(CX) = 0x05;
12297: break;
1.1 root 12298: case 0x07:
1.1.1.3 root 12299: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
12300: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
12301: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 12302: // REG16(AX) = active_code_page;
1.1 root 12303: REG16(CX) = 0x05;
12304: break;
1.1.1.25 root 12305: default:
12306: return(0x01); // function number invalid
12307: }
12308: return(0x00);
12309: }
12310:
12311: inline void msdos_int_21h_65h()
12312: {
12313: char tmp[0x10000];
12314:
12315: switch(REG8(AL)) {
1.1.1.43 root 12316: case 0x00:
12317: if(REG16(CX) >= 7) {
12318: set_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), REG16(CX) - 7);
12319: REG16(AX) = system_code_page;
12320: } else {
12321: REG16(AX) = 0x0c;
12322: m_CF = 1;
12323: }
12324: break;
1.1.1.25 root 12325: case 0x01:
12326: case 0x02:
12327: case 0x03:
12328: case 0x04:
12329: case 0x05:
12330: case 0x06:
12331: case 0x07:
12332: {
12333: UINT16 result = get_extended_country_info(REG8(AL));
12334: if(result) {
12335: REG16(AX) = result;
12336: m_CF = 1;
12337: } else {
12338: REG16(AX) = active_code_page; // FIXME: is this correct???
12339: }
12340: }
12341: break;
1.1 root 12342: case 0x20:
1.1.1.25 root 12343: case 0xa0:
1.1.1.19 root 12344: memset(tmp, 0, sizeof(tmp));
12345: tmp[0] = REG8(DL);
1.1 root 12346: my_strupr(tmp);
12347: REG8(DL) = tmp[0];
12348: break;
12349: case 0x21:
1.1.1.25 root 12350: case 0xa1:
1.1 root 12351: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 12352: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 12353: my_strupr(tmp);
1.1.1.3 root 12354: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 12355: break;
12356: case 0x22:
1.1.1.25 root 12357: case 0xa2:
1.1.1.3 root 12358: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 12359: break;
1.1.1.25 root 12360: case 0x23:
12361: // FIXME: need to check multi-byte (kanji) charactre?
1.1.1.45 root 12362: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
1.1.1.25 root 12363: // 826dh/828eh: multi-byte (kanji) N and n
1.1.1.45 root 12364: REG16(AX) = 0x00;
12365: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
12366: // 8278h/8299h: multi-byte (kanji) Y and y
1.1.1.25 root 12367: REG16(AX) = 0x01;
12368: } else {
12369: REG16(AX) = 0x02;
12370: }
12371: break;
1.1 root 12372: default:
1.1.1.22 root 12373: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 12374: REG16(AX) = 0x01;
1.1.1.3 root 12375: m_CF = 1;
1.1 root 12376: break;
12377: }
12378: }
12379:
12380: inline void msdos_int_21h_66h()
12381: {
12382: switch(REG8(AL)) {
12383: case 0x01:
12384: REG16(BX) = active_code_page;
12385: REG16(DX) = system_code_page;
12386: break;
12387: case 0x02:
12388: if(active_code_page == REG16(BX)) {
12389: REG16(AX) = 0xeb41;
12390: } else if(_setmbcp(REG16(BX)) == 0) {
12391: active_code_page = REG16(BX);
1.1.1.17 root 12392: msdos_nls_tables_update();
1.1 root 12393: REG16(AX) = 0xeb41;
1.1.1.32 root 12394: SetConsoleCP(active_code_page);
12395: SetConsoleOutputCP(active_code_page);
1.1 root 12396: } else {
12397: REG16(AX) = 0x25;
1.1.1.3 root 12398: m_CF = 1;
1.1 root 12399: }
12400: break;
12401: default:
1.1.1.22 root 12402: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 12403: REG16(AX) = 0x01;
1.1.1.3 root 12404: m_CF = 1;
1.1 root 12405: break;
12406: }
12407: }
12408:
12409: inline void msdos_int_21h_67h()
12410: {
12411: process_t *process = msdos_process_info_get(current_psp);
12412:
12413: if(REG16(BX) <= MAX_FILES) {
12414: process->max_files = max(REG16(BX), 20);
12415: } else {
12416: REG16(AX) = 0x08;
1.1.1.3 root 12417: m_CF = 1;
1.1 root 12418: }
12419: }
12420:
12421: inline void msdos_int_21h_68h()
12422: {
12423: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 12424: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 12425:
1.1.1.20 root 12426: if(fd < process->max_files && file_handler[fd].valid) {
12427: // fflush(_fdopen(fd, ""));
1.1 root 12428: } else {
12429: REG16(AX) = 0x06;
1.1.1.3 root 12430: m_CF = 1;
1.1 root 12431: }
12432: }
12433:
12434: inline void msdos_int_21h_69h()
12435: {
1.1.1.3 root 12436: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12437: char path[] = "A:\\";
12438: char volume_label[MAX_PATH];
12439: DWORD serial_number = 0;
12440: char file_system[MAX_PATH];
12441:
12442: if(REG8(BL) == 0) {
12443: path[0] = 'A' + _getdrive() - 1;
12444: } else {
12445: path[0] = 'A' + REG8(BL) - 1;
12446: }
12447:
12448: switch(REG8(AL)) {
12449: case 0x00:
12450: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
12451: info->info_level = 0;
12452: info->serial_number = serial_number;
12453: memset(info->volume_label, 0x20, 11);
12454: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
12455: memset(info->file_system, 0x20, 8);
12456: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
12457: } else {
12458: REG16(AX) = errno;
1.1.1.3 root 12459: m_CF = 1;
1.1 root 12460: }
12461: break;
12462: case 0x01:
12463: REG16(AX) = 0x03;
1.1.1.3 root 12464: m_CF = 1;
1.1.1.45 root 12465: break;
12466: default:
12467: 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));
12468: REG16(AX) = 0x01;
12469: m_CF = 1;
12470: break;
1.1 root 12471: }
12472: }
12473:
12474: inline void msdos_int_21h_6ah()
12475: {
12476: REG8(AH) = 0x68;
12477: msdos_int_21h_68h();
12478: }
12479:
12480: inline void msdos_int_21h_6bh()
12481: {
1.1.1.45 root 12482: REG8(AL) = 0x00;
1.1 root 12483: }
12484:
12485: inline void msdos_int_21h_6ch(int lfn)
12486: {
1.1.1.45 root 12487: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 12488: int mode = REG8(BL) & 0x03;
12489:
12490: if(mode < 0x03) {
1.1.1.29 root 12491: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 12492: // file exists
12493: if(REG8(DL) & 1) {
1.1.1.37 root 12494: int fd = -1;
12495: int sio_port = 0;
12496: int lpt_port = 0;
1.1 root 12497:
1.1.1.45 root 12498: if(msdos_is_device_path(path)) {
12499: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
1.1.1.11 root 12500: } else {
1.1.1.13 root 12501: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 12502: }
1.1 root 12503: if(fd != -1) {
12504: REG16(AX) = fd;
12505: REG16(CX) = 1;
1.1.1.45 root 12506: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 12507: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 12508: } else {
12509: REG16(AX) = errno;
1.1.1.3 root 12510: m_CF = 1;
1.1 root 12511: }
12512: } else if(REG8(DL) & 2) {
12513: int attr = GetFileAttributes(path);
1.1.1.37 root 12514: int fd = -1;
12515: int sio_port = 0;
12516: int lpt_port = 0;
1.1 root 12517:
1.1.1.45 root 12518: if(msdos_is_device_path(path)) {
12519: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
1.1 root 12520: } else {
12521: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
12522: }
12523: if(fd != -1) {
12524: if(attr == -1) {
12525: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
12526: }
12527: SetFileAttributes(path, attr);
12528: REG16(AX) = fd;
12529: REG16(CX) = 3;
1.1.1.45 root 12530: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 12531: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 12532: } else {
12533: REG16(AX) = errno;
1.1.1.3 root 12534: m_CF = 1;
1.1 root 12535: }
12536: } else {
12537: REG16(AX) = 0x50;
1.1.1.3 root 12538: m_CF = 1;
1.1 root 12539: }
12540: } else {
12541: // file not exists
12542: if(REG8(DL) & 0x10) {
12543: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
12544:
12545: if(fd != -1) {
12546: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
12547: REG16(AX) = fd;
12548: REG16(CX) = 2;
12549: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 12550: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 12551: } else {
12552: REG16(AX) = errno;
1.1.1.3 root 12553: m_CF = 1;
1.1 root 12554: }
12555: } else {
12556: REG16(AX) = 0x02;
1.1.1.3 root 12557: m_CF = 1;
1.1 root 12558: }
12559: }
12560: } else {
12561: REG16(AX) = 0x0c;
1.1.1.3 root 12562: m_CF = 1;
1.1 root 12563: }
12564: }
12565:
1.1.1.43 root 12566: inline void msdos_int_21h_70h()
12567: {
12568: switch(REG8(AL)) {
1.1.1.48 root 12569: case 0x00: // get ??? info
12570: case 0x01: // set above info
12571: // 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));
12572: REG16(AX) = 0x7000;
12573: m_CF = 1;
12574: break;
12575: case 0x02: // set general internationalization info
1.1.1.43 root 12576: if(REG16(CX) >= 7) {
12577: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
12578: msdos_nls_tables_update();
12579: set_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(SI) + 7), REG16(CX) - 7);
12580: REG16(AX) = system_code_page;
12581: } else {
12582: REG16(AX) = 0x0c;
12583: m_CF = 1;
12584: }
12585: break;
12586: default:
12587: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 12588: REG16(AX) = 0x7000;
1.1.1.43 root 12589: m_CF = 1;
12590: break;
12591: }
12592: }
12593:
1.1 root 12594: inline void msdos_int_21h_710dh()
12595: {
12596: // reset drive
12597: }
12598:
1.1.1.48 root 12599: inline void msdos_int_21h_7141h()
1.1.1.17 root 12600: {
12601: if(REG16(SI) == 0) {
1.1.1.48 root 12602: msdos_int_21h_41h(1);
1.1.1.17 root 12603: return;
12604: }
12605: if(REG16(SI) != 1) {
12606: REG16(AX) = 5;
12607: m_CF = 1;
12608: }
12609: /* wild card and matching attributes... */
12610: char tmp[MAX_PATH * 2];
12611: // copy search pathname (and quick check overrun)
12612: ZeroMemory(tmp, sizeof(tmp));
12613: tmp[MAX_PATH - 1] = '\0';
12614: tmp[MAX_PATH] = 1;
12615: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
12616:
12617: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
12618: REG16(AX) = 1;
12619: m_CF = 1;
12620: return;
12621: }
12622: for(char *s = tmp; *s; ++s) {
12623: if(*s == '/') {
12624: *s = '\\';
12625: }
12626: }
12627: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
12628: if(tmp_name) {
12629: ++tmp_name;
12630: } else {
12631: tmp_name = strchr(tmp, ':');
12632: tmp_name = tmp_name ? tmp_name + 1 : tmp;
12633: }
12634:
12635: WIN32_FIND_DATAA fd;
12636: HANDLE fh = FindFirstFileA(tmp, &fd);
12637: if(fh == INVALID_HANDLE_VALUE) {
12638: REG16(AX) = 2;
12639: m_CF = 1;
12640: return;
12641: }
12642: do {
12643: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
12644: strcpy(tmp_name, fd.cFileName);
1.1.1.48 root 12645: if(remove(msdos_trimmed_path(tmp, 1))) {
1.1.1.17 root 12646: REG16(AX) = 5;
12647: m_CF = 1;
12648: break;
12649: }
12650: }
12651: } while(FindNextFileA(fh, &fd));
12652: if(!m_CF) {
12653: if(GetLastError() != ERROR_NO_MORE_FILES) {
12654: m_CF = 1;
12655: REG16(AX) = 2;
12656: }
12657: }
12658: FindClose(fh);
12659: }
12660:
1.1 root 12661: inline void msdos_int_21h_714eh()
12662: {
12663: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 12664: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
12665: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12666: WIN32_FIND_DATA fd;
12667:
1.1.1.13 root 12668: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
12669: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12670: FindClose(dtainfo->find_handle);
12671: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12672: }
12673: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 12674: dtainfo->allowable_mask = REG8(CL);
12675: dtainfo->required_mask = REG8(CH);
12676: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 12677:
1.1.1.14 root 12678: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
12679: dtainfo->allowable_mask &= ~8;
1.1 root 12680: }
1.1.1.14 root 12681: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
12682: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 12683: if(!FindNextFile(dtainfo->find_handle, &fd)) {
12684: FindClose(dtainfo->find_handle);
12685: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12686: break;
12687: }
12688: }
12689: }
1.1.1.13 root 12690: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 12691: find->attrib = fd.dwFileAttributes;
12692: msdos_find_file_conv_local_time(&fd);
12693: if(REG16(SI) == 0) {
12694: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
12695: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
12696: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
12697: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
12698: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
12699: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
12700: } else {
12701: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
12702: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
12703: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
12704: }
12705: find->size_hi = fd.nFileSizeHigh;
12706: find->size_lo = fd.nFileSizeLow;
12707: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 12708: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 12709: REG16(AX) = dtainfo - dtalist + 1;
12710: } else if(dtainfo->allowable_mask & 8) {
1.1 root 12711: // volume label
12712: find->attrib = 8;
12713: find->size_hi = find->size_lo = 0;
12714: strcpy(find->full_name, process->volume_label);
12715: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 12716: dtainfo->allowable_mask &= ~8;
12717: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 12718: } else {
12719: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 12720: m_CF = 1;
1.1 root 12721: }
12722: }
12723:
12724: inline void msdos_int_21h_714fh()
12725: {
12726: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 12727: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 12728: WIN32_FIND_DATA fd;
12729:
1.1.1.14 root 12730: if(REG16(BX) - 1u >= MAX_DTAINFO) {
12731: REG16(AX) = 6;
1.1.1.13 root 12732: m_CF = 1;
12733: return;
12734: }
1.1.1.14 root 12735: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 12736: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12737: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 12738: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 12739: if(!FindNextFile(dtainfo->find_handle, &fd)) {
12740: FindClose(dtainfo->find_handle);
12741: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12742: break;
12743: }
12744: }
12745: } else {
1.1.1.13 root 12746: FindClose(dtainfo->find_handle);
12747: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12748: }
12749: }
1.1.1.13 root 12750: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 12751: find->attrib = fd.dwFileAttributes;
12752: msdos_find_file_conv_local_time(&fd);
12753: if(REG16(SI) == 0) {
12754: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
12755: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
12756: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
12757: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
12758: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
12759: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
12760: } else {
12761: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
12762: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
12763: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
12764: }
12765: find->size_hi = fd.nFileSizeHigh;
12766: find->size_lo = fd.nFileSizeLow;
12767: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 12768: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 12769: } else if(dtainfo->allowable_mask & 8) {
1.1 root 12770: // volume label
12771: find->attrib = 8;
12772: find->size_hi = find->size_lo = 0;
12773: strcpy(find->full_name, process->volume_label);
12774: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 12775: dtainfo->allowable_mask &= ~8;
1.1 root 12776: } else {
12777: REG16(AX) = 0x12;
1.1.1.3 root 12778: m_CF = 1;
1.1 root 12779: }
12780: }
12781:
12782: inline void msdos_int_21h_71a0h()
12783: {
12784: DWORD max_component_len, file_sys_flag;
12785:
1.1.1.14 root 12786: if(GetVolumeInformation((char *)(mem + SREG_BASE(DS) + REG16(DX)), NULL, 0, NULL, &max_component_len, &file_sys_flag, REG16(CX) == 0 ? NULL : (char *)(mem + SREG_BASE(ES) + REG16(DI)), REG16(CX))) {
12787: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
12788: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 12789: REG16(CX) = (UINT16)max_component_len; // 255
12790: REG16(DX) = (UINT16)max_component_len + 5; // 260
12791: } else {
12792: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12793: m_CF = 1;
1.1 root 12794: }
12795: }
12796:
12797: inline void msdos_int_21h_71a1h()
12798: {
1.1.1.14 root 12799: if(REG16(BX) - 1u >= MAX_DTAINFO) {
12800: REG16(AX) = 6;
1.1.1.13 root 12801: m_CF = 1;
12802: return;
12803: }
1.1.1.14 root 12804: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 12805: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12806: FindClose(dtainfo->find_handle);
12807: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12808: }
12809: }
12810:
12811: inline void msdos_int_21h_71a6h()
12812: {
12813: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 12814: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12815:
1.1.1.3 root 12816: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12817: struct _stat64 status;
12818: DWORD serial_number = 0;
12819:
1.1.1.20 root 12820: if(fd < process->max_files && file_handler[fd].valid) {
12821: if(_fstat64(fd, &status) == 0) {
12822: if(file_handler[fd].path[1] == ':') {
1.1 root 12823: // NOTE: we need to consider the network file path "\\host\share\"
12824: char volume[] = "A:\\";
1.1.1.20 root 12825: volume[0] = file_handler[fd].path[1];
1.1 root 12826: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
12827: }
1.1.1.20 root 12828: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 12829: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
12830: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
12831: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
12832: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
12833: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
12834: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
12835: *(UINT32 *)(buffer + 0x1c) = serial_number;
12836: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
12837: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
12838: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 12839: // this is dummy id and it will be changed when it is reopened...
1.1 root 12840: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 12841: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 12842: } else {
12843: REG16(AX) = errno;
1.1.1.3 root 12844: m_CF = 1;
1.1 root 12845: }
12846: } else {
12847: REG16(AX) = 0x06;
1.1.1.3 root 12848: m_CF = 1;
1.1 root 12849: }
12850: }
12851:
12852: inline void msdos_int_21h_71a7h()
12853: {
12854: switch(REG8(BL)) {
12855: case 0x00:
1.1.1.3 root 12856: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 12857: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12858: m_CF = 1;
1.1 root 12859: }
12860: break;
12861: case 0x01:
12862: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 12863: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 12864: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12865: m_CF = 1;
1.1 root 12866: }
12867: break;
12868: default:
1.1.1.22 root 12869: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 12870: REG16(AX) = 0x7100;
1.1.1.3 root 12871: m_CF = 1;
1.1 root 12872: break;
12873: }
12874: }
12875:
12876: inline void msdos_int_21h_71a8h()
12877: {
12878: if(REG8(DH) == 0) {
12879: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 12880: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 12881: memset(fcb, 0x20, sizeof(fcb));
12882: int len = strlen(tmp);
1.1.1.21 root 12883: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 12884: if(tmp[i] == '.') {
12885: pos = 8;
12886: } else {
12887: if(msdos_lead_byte_check(tmp[i])) {
12888: fcb[pos++] = tmp[i++];
12889: }
12890: fcb[pos++] = tmp[i];
12891: }
12892: }
1.1.1.3 root 12893: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 12894: } else {
1.1.1.3 root 12895: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 12896: }
12897: }
12898:
1.1.1.22 root 12899: inline void msdos_int_21h_71aah()
12900: {
12901: char drv[] = "A:", path[MAX_PATH];
12902: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
12903:
12904: if(REG8(BL) == 0) {
12905: drv[0] = 'A' + _getdrive() - 1;
12906: } else {
12907: drv[0] = 'A' + REG8(BL) - 1;
12908: }
12909: switch(REG8(BH)) {
12910: case 0x00:
1.1.1.44 root 12911: if(msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12912: REG16(AX) = 0x0f; // invalid drive
12913: m_CF = 1;
12914: } else if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
12915: REG16(AX) = 0x03; // path not found
1.1.1.22 root 12916: m_CF = 1;
12917: }
12918: break;
12919: case 0x01:
1.1.1.44 root 12920: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12921: REG16(AX) = 0x0f; // invalid drive
12922: m_CF = 1;
12923: } else if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
1.1.1.22 root 12924: REG16(AX) = 0x0f; // invalid drive
12925: m_CF = 1;
12926: }
12927: break;
12928: case 0x02:
1.1.1.44 root 12929: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12930: REG16(AX) = 0x0f; // invalid drive
12931: m_CF = 1;
12932: } else if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
1.1.1.22 root 12933: REG16(AX) = 0x0f; // invalid drive
12934: m_CF = 1;
12935: } else if(strncmp(path, "\\??\\", 4) != 0) {
12936: REG16(AX) = 0x0f; // invalid drive
12937: m_CF = 1;
12938: } else {
12939: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
12940: }
12941: break;
12942: default:
12943: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 12944: REG16(AX) = 0x7100;
1.1.1.22 root 12945: m_CF = 1;
12946: break;
12947: }
12948: }
12949:
1.1.1.14 root 12950: inline void msdos_int_21h_7300h()
12951: {
1.1.1.44 root 12952: REG8(AL) = REG8(CL);
12953: REG8(AH) = 0;
1.1.1.14 root 12954: }
12955:
12956: inline void msdos_int_21h_7302h()
12957: {
12958: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
12959: UINT16 seg, ofs;
12960:
12961: if(REG16(CX) < 0x3f) {
12962: REG8(AL) = 0x18;
12963: m_CF = 1;
12964: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
12965: REG8(AL) = 0xff;
12966: m_CF = 1;
12967: } else {
12968: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
12969: }
12970: }
12971:
1.1 root 12972: inline void msdos_int_21h_7303h()
12973: {
1.1.1.3 root 12974: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
12975: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 12976: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
12977:
12978: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
12979: info->size_of_structure = sizeof(ext_space_info_t);
12980: info->structure_version = 0;
12981: info->sectors_per_cluster = sectors_per_cluster;
12982: info->bytes_per_sector = bytes_per_sector;
12983: info->available_clusters_on_drive = free_clusters;
12984: info->total_clusters_on_drive = total_clusters;
12985: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
12986: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
12987: info->available_allocation_units = free_clusters; // ???
12988: info->total_allocation_units = total_clusters; // ???
12989: } else {
12990: REG16(AX) = errno;
1.1.1.3 root 12991: m_CF = 1;
1.1 root 12992: }
12993: }
12994:
1.1.1.30 root 12995: inline void msdos_int_21h_dbh()
12996: {
12997: // Novell NetWare - Workstation - Get Number of Local Drives
12998: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
12999: REG8(AL) = dos_info->last_drive;
13000: }
13001:
13002: inline void msdos_int_21h_dch()
13003: {
13004: // Novell NetWare - Connection Services - Get Connection Number
13005: REG8(AL) = 0x00;
13006: }
13007:
1.1.1.32 root 13008: inline void msdos_int_24h()
13009: {
13010: const char *message = NULL;
13011: int key = 0;
13012:
13013: for(int i = 0; i < array_length(critical_error_table); i++) {
13014: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
13015: if(active_code_page == 932) {
13016: message = critical_error_table[i].message_japanese;
13017: }
13018: if(message == NULL) {
13019: message = critical_error_table[i].message_english;
13020: }
13021: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
13022: strcpy((char *)(mem + WORK_TOP + 1), message);
13023:
13024: SREG(ES) = WORK_TOP >> 4;
13025: i386_load_segment_descriptor(ES);
13026: REG16(DI) = 0x0000;
13027: break;
13028: }
13029: }
13030: fprintf(stderr, "\n%s", message);
13031: if(!(REG8(AH) & 0x80)) {
13032: if(REG8(AH) & 0x01) {
13033: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
13034: } else {
13035: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
13036: }
13037: }
13038: fprintf(stderr, "\n");
13039:
1.1.1.33 root 13040: {
1.1.1.32 root 13041: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
1.1.1.33 root 13042: }
1.1.1.32 root 13043: if(REG8(AH) & 0x10) {
13044: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
13045: }
13046: if(REG8(AH) & 0x20) {
13047: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
13048: }
13049: if(REG8(AH) & 0x08) {
13050: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
13051: }
13052: fprintf(stderr, "? ");
13053:
13054: while(1) {
13055: while(!_kbhit()) {
13056: Sleep(10);
13057: }
13058: key = _getch();
13059:
13060: if(key == 'I' || key == 'i') {
13061: if(REG8(AH) & 0x20) {
13062: REG8(AL) = 0;
13063: break;
13064: }
13065: } else if(key == 'R' || key == 'r') {
13066: if(REG8(AH) & 0x10) {
13067: REG8(AL) = 1;
13068: break;
13069: }
13070: } else if(key == 'A' || key == 'a') {
13071: REG8(AL) = 2;
13072: break;
13073: } else if(key == 'F' || key == 'f') {
13074: if(REG8(AH) & 0x08) {
13075: REG8(AL) = 3;
13076: break;
13077: }
13078: }
13079: }
13080: fprintf(stderr, "%c\n", key);
13081: }
13082:
1.1 root 13083: inline void msdos_int_25h()
13084: {
13085: UINT16 seg, ofs;
13086: DWORD dwSize;
13087:
1.1.1.3 root 13088: #if defined(HAS_I386)
13089: I386OP(pushf)();
13090: #else
13091: PREFIX86(_pushf());
13092: #endif
1.1 root 13093:
13094: if(!(REG8(AL) < 26)) {
13095: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 13096: m_CF = 1;
1.1 root 13097: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
13098: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13099: m_CF = 1;
1.1 root 13100: } else {
13101: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
13102: char dev[64];
13103: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
13104:
13105: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
13106: if(hFile == INVALID_HANDLE_VALUE) {
13107: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13108: m_CF = 1;
1.1 root 13109: } else {
1.1.1.19 root 13110: UINT32 top_sector = REG16(DX);
13111: UINT16 sector_num = REG16(CX);
13112: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
13113:
13114: if(sector_num == 0xffff) {
13115: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
13116: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
13117: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
13118: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
13119: buffer_addr = (seg << 4) + ofs;
13120: }
13121: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
13122: // REG8(AL) = 0x02; // drive not ready
13123: // m_CF = 1;
13124: // } else
13125: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 13126: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 13127: m_CF = 1;
1.1.1.19 root 13128: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 13129: REG8(AL) = 0x0b; // read error
1.1.1.3 root 13130: m_CF = 1;
1.1 root 13131: }
13132: CloseHandle(hFile);
13133: }
13134: }
13135: }
13136:
13137: inline void msdos_int_26h()
13138: {
1.1.1.42 root 13139: // this operation may cause serious damage for drives, so support only floppy disk...
1.1 root 13140: UINT16 seg, ofs;
13141: DWORD dwSize;
13142:
1.1.1.3 root 13143: #if defined(HAS_I386)
13144: I386OP(pushf)();
13145: #else
13146: PREFIX86(_pushf());
13147: #endif
1.1 root 13148:
13149: if(!(REG8(AL) < 26)) {
13150: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 13151: m_CF = 1;
1.1 root 13152: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
13153: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13154: m_CF = 1;
1.1 root 13155: } else {
13156: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
13157: char dev[64];
13158: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
13159:
13160: if(dpb->media_type == 0xf8) {
13161: // this drive is not a floppy
1.1.1.6 root 13162: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
13163: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
13164: // }
1.1 root 13165: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13166: m_CF = 1;
1.1 root 13167: } else {
13168: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
13169: if(hFile == INVALID_HANDLE_VALUE) {
13170: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13171: m_CF = 1;
1.1 root 13172: } else {
1.1.1.19 root 13173: UINT32 top_sector = REG16(DX);
13174: UINT16 sector_num = REG16(CX);
13175: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
13176:
13177: if(sector_num == 0xffff) {
13178: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
13179: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
13180: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
13181: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
13182: buffer_addr = (seg << 4) + ofs;
13183: }
1.1 root 13184: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
13185: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13186: m_CF = 1;
1.1.1.19 root 13187: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 13188: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 13189: m_CF = 1;
1.1.1.19 root 13190: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 13191: REG8(AL) = 0x0a; // write error
1.1.1.3 root 13192: m_CF = 1;
1.1 root 13193: }
13194: CloseHandle(hFile);
13195: }
13196: }
13197: }
13198: }
13199:
13200: inline void msdos_int_27h()
13201: {
1.1.1.29 root 13202: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
13203: try {
13204: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
13205: } catch(...) {
13206: // recover the broken mcb
13207: int mcb_seg = SREG(CS) - 1;
13208: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 13209:
1.1.1.29 root 13210: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 13211: mcb->mz = 'M';
13212: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
13213:
1.1.1.29 root 13214: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 13215: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 13216: } else {
1.1.1.39 root 13217: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 13218: }
13219: } else {
13220: mcb->mz = 'Z';
1.1.1.30 root 13221: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 13222: }
13223: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
13224: }
1.1.1.3 root 13225: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 13226: }
13227:
13228: inline void msdos_int_29h()
13229: {
1.1.1.50 root 13230: msdos_putch_fast(REG8(AL));
1.1 root 13231: }
13232:
13233: inline void msdos_int_2eh()
13234: {
13235: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
13236: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 13237: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 13238: char *token = my_strtok(tmp, " ");
13239: strcpy(command, token);
13240: strcpy(opt, token + strlen(token) + 1);
13241:
13242: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
13243: param->env_seg = 0;
13244: param->cmd_line.w.l = 44;
13245: param->cmd_line.w.h = (WORK_TOP >> 4);
13246: param->fcb1.w.l = 24;
13247: param->fcb1.w.h = (WORK_TOP >> 4);
13248: param->fcb2.w.l = 24;
13249: param->fcb2.w.h = (WORK_TOP >> 4);
13250:
13251: memset(mem + WORK_TOP + 24, 0x20, 20);
13252:
13253: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
13254: cmd_line->len = strlen(opt);
13255: strcpy(cmd_line->cmd, opt);
13256: cmd_line->cmd[cmd_line->len] = 0x0d;
13257:
1.1.1.28 root 13258: try {
13259: if(msdos_process_exec(command, param, 0)) {
13260: REG16(AX) = 0xffff; // error before processing command
13261: } else {
13262: // set flag to set retval to ax when the started process is terminated
13263: process_t *process = msdos_process_info_get(current_psp);
13264: process->called_by_int2eh = true;
13265: }
13266: } catch(...) {
13267: REG16(AX) = 0xffff; // error before processing command
13268: }
1.1 root 13269: }
13270:
1.1.1.29 root 13271: inline void msdos_int_2fh_05h()
13272: {
13273: switch(REG8(AL)) {
13274: case 0x00:
1.1.1.49 root 13275: // critical error handler is installed
1.1.1.32 root 13276: REG8(AL) = 0xff;
13277: break;
13278: case 0x01:
13279: case 0x02:
13280: for(int i = 0; i < array_length(standard_error_table); i++) {
13281: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
13282: const char *message = NULL;
13283: if(active_code_page == 932) {
13284: message = standard_error_table[i].message_japanese;
13285: }
13286: if(message == NULL) {
13287: message = standard_error_table[i].message_english;
13288: }
13289: strcpy((char *)(mem + WORK_TOP), message);
13290:
13291: SREG(ES) = WORK_TOP >> 4;
13292: i386_load_segment_descriptor(ES);
13293: REG16(DI) = 0x0000;
13294: REG8(AL) = 0x01;
13295: break;
13296: }
13297: }
1.1.1.29 root 13298: break;
13299: default:
13300: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.49 root 13301: REG16(AX) = 0x01;
1.1.1.29 root 13302: m_CF = 1;
13303: }
13304: }
13305:
1.1.1.44 root 13306: inline void msdos_int_2fh_06h()
13307: {
13308: switch(REG8(AL)) {
13309: case 0x00:
13310: // ASSIGN is not installed
1.1.1.49 root 13311: // REG8(AL) = 0x00;
1.1.1.44 root 13312: break;
13313: case 0x01:
13314: // this call is available from within MIRROR.COM even if ASSIGN is not installed
13315: REG16(AX) = 0x01;
13316: m_CF = 1;
13317: break;
13318: default:
13319: 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));
13320: REG16(AX) = 0x01;
13321: m_CF = 1;
13322: break;
13323: }
13324: }
13325:
1.1.1.22 root 13326: inline void msdos_int_2fh_11h()
13327: {
13328: switch(REG8(AL)) {
13329: case 0x00:
1.1.1.29 root 13330: if(i386_read_stack() == 0xdada) {
1.1.1.53! root 13331: #ifdef SUPPORT_MSCDEX
! 13332: // MSCDEX is installed
! 13333: REG8(AL) = 0xff;
! 13334: i386_write_stack(0xadad);
! 13335: #else
1.1.1.29 root 13336: // MSCDEX is not installed
13337: // REG8(AL) = 0x00;
1.1.1.53! root 13338: #endif
1.1.1.29 root 13339: } else {
13340: // Network Redirector is not installed
13341: // REG8(AL) = 0x00;
13342: }
1.1.1.22 root 13343: break;
13344: default:
1.1.1.43 root 13345: // unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.29 root 13346: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 13347: m_CF = 1;
13348: break;
13349: }
13350: }
13351:
1.1.1.21 root 13352: inline void msdos_int_2fh_12h()
13353: {
13354: switch(REG8(AL)) {
1.1.1.22 root 13355: case 0x00:
1.1.1.29 root 13356: // DOS 3.0+ internal functions are installed
1.1.1.22 root 13357: REG8(AL) = 0xff;
13358: break;
1.1.1.29 root 13359: // case 0x01: // DOS 3.0+ internal - Close Current File
13360: case 0x02:
13361: {
13362: UINT16 stack = i386_read_stack();
13363: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
13364: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
13365: i386_load_segment_descriptor(ES);
13366: }
13367: break;
1.1.1.30 root 13368: case 0x03:
13369: SREG(DS) = (DEVICE_TOP >> 4);
13370: i386_load_segment_descriptor(DS);
13371: break;
1.1.1.29 root 13372: case 0x04:
13373: {
13374: UINT16 stack = i386_read_stack();
13375: REG8(AL) = (stack == '/') ? '\\' : stack;
13376: #if defined(HAS_I386)
13377: m_ZF = (REG8(AL) == '\\');
13378: #else
13379: m_ZeroVal = (REG8(AL) != '\\');
13380: #endif
13381: }
13382: break;
13383: case 0x05:
1.1.1.49 root 13384: {
13385: UINT16 c = i386_read_stack();
13386: if((c >> 0) & 0xff) {
13387: msdos_putch((c >> 0) & 0xff);
13388: }
13389: if((c >> 8) & 0xff) {
13390: msdos_putch((c >> 8) & 0xff);
13391: }
13392: }
1.1.1.29 root 13393: break;
1.1.1.49 root 13394: // case 0x06: // DOS 3.0+ internal - Invoke Critical Error
1.1.1.29 root 13395: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
13396: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
1.1.1.49 root 13397: // case 0x09: // DOS 3.0+ internal - Flush and Free Disk Buffer
1.1.1.29 root 13398: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
13399: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
13400: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
13401: case 0x0d:
13402: {
13403: SYSTEMTIME time;
13404: FILETIME file_time;
13405: WORD dos_date, dos_time;
13406: GetLocalTime(&time);
13407: SystemTimeToFileTime(&time, &file_time);
13408: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
13409: REG16(AX) = dos_date;
13410: REG16(DX) = dos_time;
13411: }
13412: break;
13413: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
13414: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
13415: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
13416: case 0x11:
13417: {
13418: char path[MAX_PATH], *p;
13419: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
13420: my_strupr(path);
13421: while((p = my_strchr(path, '/')) != NULL) {
13422: *p = '\\';
13423: }
13424: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
13425: }
13426: break;
13427: case 0x12:
13428: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
13429: break;
13430: case 0x13:
13431: {
13432: char tmp[2] = {0};
13433: tmp[0] = i386_read_stack();
13434: my_strupr(tmp);
13435: REG8(AL) = tmp[0];
13436: }
13437: break;
13438: case 0x14:
13439: #if defined(HAS_I386)
13440: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
13441: #else
13442: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
13443: #endif
13444: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
13445: break;
13446: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 13447: case 0x16:
13448: if(REG16(BX) < 20) {
13449: SREG(ES) = SFT_TOP >> 4;
13450: i386_load_segment_descriptor(ES);
13451: REG16(DI) = 6 + 0x3b * REG16(BX);
13452:
13453: // update system file table
13454: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
13455: if(file_handler[REG16(BX)].valid) {
13456: int count = 0;
13457: for(int i = 0; i < 20; i++) {
13458: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
13459: count++;
13460: }
13461: }
13462: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
13463: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
13464: _lseek(REG16(BX), 0, SEEK_END);
13465: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
13466: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
13467: } else {
13468: memset(sft, 0, 0x3b);
13469: }
13470: } else {
13471: REG16(AX) = 0x06;
13472: m_CF = 1;
13473: }
13474: break;
1.1.1.49 root 13475: case 0x17:
13476: {
13477: UINT16 drive = i386_read_stack();
13478: if(msdos_is_valid_drive(drive)) {
13479: msdos_cds_update(drive);
13480: }
13481: REG16(SI) = 88 * drive;
13482: SREG(DS) = (CDS_TOP >> 4);
13483: i386_load_segment_descriptor(DS);
13484: }
13485: break;
1.1.1.29 root 13486: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
13487: // case 0x19: // DOS 3.0+ internal - Set Drive???
13488: case 0x1a:
13489: {
13490: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
13491: if(path[1] == ':') {
13492: if(path[0] >= 'a' && path[0] <= 'z') {
13493: REG8(AL) = path[0] - 'a' + 1;
13494: } else if(path[0] >= 'A' && path[0] <= 'Z') {
13495: REG8(AL) = path[0] - 'A' + 1;
13496: } else {
13497: REG8(AL) = 0xff; // invalid
13498: }
13499: strcpy(full, path);
13500: strcpy(path, full + 2);
13501: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
13502: if(full[0] >= 'a' && full[0] <= 'z') {
13503: REG8(AL) = full[0] - 'a' + 1;
13504: } else if(full[0] >= 'A' && full[0] <= 'Z') {
13505: REG8(AL) = full[0] - 'A' + 1;
13506: } else {
13507: REG8(AL) = 0xff; // invalid
13508: }
13509: } else {
13510: REG8(AL) = 0x00; // default
13511: }
13512: }
13513: break;
13514: case 0x1b:
13515: {
13516: int year = REG16(CX) + 1980;
13517: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
13518: }
13519: break;
13520: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
13521: // case 0x1d: // DOS 3.0+ internal - Sum Memory
13522: case 0x1e:
13523: {
13524: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
13525: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
13526: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
13527: #if defined(HAS_I386)
13528: m_ZF = (strcmp(full_1st, full_2nd) == 0);
13529: #else
13530: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
13531: #endif
13532: } else {
13533: #if defined(HAS_I386)
13534: m_ZF = (strcmp(path_1st, path_2nd) == 0);
13535: #else
13536: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
13537: #endif
13538: }
13539: }
13540: break;
1.1.1.49 root 13541: case 0x1f:
13542: {
13543: UINT16 drive = i386_read_stack();
13544: if(msdos_is_valid_drive(drive)) {
13545: msdos_cds_update(drive);
13546: }
13547: REG16(SI) = 88 * drive;
13548: SREG(ES) = (CDS_TOP >> 4);
13549: i386_load_segment_descriptor(ES);
13550: }
13551: break;
1.1.1.21 root 13552: case 0x20:
13553: {
13554: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
13555:
13556: if(fd < 20) {
13557: SREG(ES) = current_psp;
13558: i386_load_segment_descriptor(ES);
13559: REG16(DI) = offsetof(psp_t, file_table) + fd;
13560: } else {
13561: REG16(AX) = 0x06;
13562: m_CF = 1;
13563: }
13564: }
13565: break;
1.1.1.29 root 13566: case 0x21:
13567: msdos_int_21h_60h(0);
13568: break;
1.1.1.49 root 13569: case 0x22:
13570: {
13571: sda_t *sda = (sda_t *)(mem + SDA_TOP);
13572: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00) != 0xff) {
13573: sda->extended_error_code = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00);
13574: }
13575: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01) != 0xff) {
13576: sda->error_class = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01);
13577: }
13578: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02) != 0xff) {
13579: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02);
13580: }
13581: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03) != 0xff) {
13582: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03);
13583: }
13584: }
13585: break;
1.1.1.29 root 13586: // case 0x23: // DOS 3.0+ internal - Check If Character Device
13587: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
13588: case 0x25:
13589: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
13590: break;
13591: case 0x26:
13592: REG8(AL) = REG8(CL);
13593: msdos_int_21h_3dh();
13594: break;
13595: case 0x27:
13596: msdos_int_21h_3eh();
13597: break;
13598: case 0x28:
13599: REG16(AX) = REG16(BP);
13600: msdos_int_21h_42h();
13601: break;
13602: case 0x29:
13603: msdos_int_21h_3fh();
13604: break;
13605: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
13606: case 0x2b:
13607: REG16(AX) = REG16(BP);
13608: msdos_int_21h_44h();
13609: break;
13610: case 0x2c:
13611: REG16(BX) = DEVICE_TOP >> 4;
13612: REG16(AX) = 22;
13613: break;
13614: case 0x2d:
13615: {
13616: sda_t *sda = (sda_t *)(mem + SDA_TOP);
13617: REG16(AX) = sda->extended_error_code;
13618: }
13619: break;
13620: case 0x2e:
13621: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32 root 13622: SREG(ES) = 0x0001;
13623: i386_load_segment_descriptor(ES);
13624: REG16(DI) = 0x00;
13625: } else if(REG8(DL) == 0x08) {
1.1.1.49 root 13626: // dummy parameter error message read routine is at fffc:0010
13627: SREG(ES) = DUMMY_TOP >> 4;
1.1.1.22 root 13628: i386_load_segment_descriptor(ES);
1.1.1.32 root 13629: REG16(DI) = 0x0010;
1.1.1.22 root 13630: }
13631: break;
1.1.1.29 root 13632: case 0x2f:
13633: if(REG16(DX) != 0) {
1.1.1.30 root 13634: dos_major_version = REG8(DL);
13635: dos_minor_version = REG8(DH);
1.1.1.29 root 13636: } else {
13637: REG8(DL) = 7;
13638: REG8(DH) = 10;
13639: }
13640: break;
13641: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
13642: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 13643: default:
13644: 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));
13645: REG16(AX) = 0x01;
13646: m_CF = 1;
13647: break;
13648: }
13649: }
13650:
1.1.1.30 root 13651: inline void msdos_int_2fh_13h()
13652: {
13653: static UINT16 prevDS = 0, prevDX = 0;
13654: static UINT16 prevES = 0, prevBX = 0;
13655: UINT16 tmp;
13656:
13657: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
13658: i386_load_segment_descriptor(DS);
13659: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
13660:
13661: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
13662: i386_load_segment_descriptor(ES);
13663: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
13664: }
13665:
1.1.1.22 root 13666: inline void msdos_int_2fh_14h()
13667: {
13668: switch(REG8(AL)) {
13669: case 0x00:
1.1.1.29 root 13670: // NLSFUNC.COM is installed
13671: REG8(AL) = 0xff;
1.1.1.25 root 13672: break;
13673: case 0x01:
13674: case 0x03:
13675: REG8(AL) = 0x00;
13676: active_code_page = REG16(BX);
13677: msdos_nls_tables_update();
13678: break;
13679: case 0x02:
13680: REG8(AL) = get_extended_country_info(REG16(BP));
13681: break;
13682: case 0x04:
1.1.1.42 root 13683: for(int i = 0;; i++) {
13684: if(country_table[i].code == REG16(DX)) {
13685: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
13686: break;
13687: } else if(country_table[i].code == -1) {
13688: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
13689: break;
13690: }
13691: }
1.1.1.25 root 13692: REG8(AL) = 0x00;
1.1.1.22 root 13693: break;
13694: default:
13695: 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));
13696: REG16(AX) = 0x01;
13697: m_CF = 1;
13698: break;
13699: }
13700: }
13701:
13702: inline void msdos_int_2fh_15h()
13703: {
13704: switch(REG8(AL)) {
1.1.1.29 root 13705: case 0x00: // CD-ROM - Installation Check
13706: if(REG16(BX) == 0x0000) {
1.1.1.53! root 13707: #ifdef SUPPORT_MSCDEX
1.1.1.43 root 13708: // MSCDEX is installed
13709: REG16(BX) = 0;
13710: for(int i = 0, n = 0; i < 26; i++) {
1.1.1.44 root 13711: if(msdos_is_cdrom_drive(i)) {
13712: if(REG16(BX) == 0) {
13713: REG16(CX) = i;
1.1.1.43 root 13714: }
1.1.1.44 root 13715: REG16(BX)++;
1.1.1.43 root 13716: }
13717: }
13718: #else
1.1.1.29 root 13719: // MSCDEX is not installed
13720: // REG8(AL) = 0x00;
1.1.1.43 root 13721: #endif
1.1.1.29 root 13722: } else {
13723: // GRAPHICS.COM is not installed
13724: // REG8(AL) = 0x00;
13725: }
1.1.1.22 root 13726: break;
1.1.1.43 root 13727: case 0x0b:
1.1.1.44 root 13728: // this call is available from within DOSSHELL even if MSCDEX is not installed
13729: REG16(AX) = msdos_is_cdrom_drive(REG8(CL)) ? 0x5ad8 : 0x0000;
13730: REG16(BX) = 0xadad;
1.1.1.43 root 13731: break;
13732: case 0x0d:
1.1.1.44 root 13733: for(int i = 0, n = 0; i < 26; i++) {
13734: if(msdos_is_cdrom_drive(i)) {
13735: mem[SREG_BASE(ES) + REG16(BX) + (n++)] = i;
1.1.1.43 root 13736: }
13737: }
13738: break;
1.1.1.22 root 13739: case 0xff:
1.1.1.29 root 13740: if(REG16(BX) == 0x0000) {
13741: // CORELCDX is not installed
13742: } else {
13743: 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));
13744: REG16(AX) = 0x01;
13745: m_CF = 1;
13746: }
1.1.1.22 root 13747: break;
1.1.1.21 root 13748: default:
1.1.1.22 root 13749: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.21 root 13750: REG16(AX) = 0x01;
13751: m_CF = 1;
13752: break;
13753: }
13754: }
13755:
1.1 root 13756: inline void msdos_int_2fh_16h()
13757: {
13758: switch(REG8(AL)) {
13759: case 0x00:
1.1.1.14 root 13760: if(no_windows) {
1.1.1.29 root 13761: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
13762: // REG8(AL) = 0x00;
1.1.1.14 root 13763: } else {
1.1.1.30 root 13764: REG8(AL) = win_major_version;
13765: REG8(AH) = win_minor_version;
1.1 root 13766: }
13767: break;
1.1.1.43 root 13768: case 0x05: // Windows Enhanced Mode & 286 DOSX Init Broadcast
1.1.1.30 root 13769: // from DOSBox
13770: i386_set_a20_line(1);
13771: break;
1.1.1.49 root 13772: case 0x06: // Windows Enhanced Mode & 286 DOSX Exit Broadcast
1.1.1.43 root 13773: case 0x08: // Windows Enhanced Mode Init Complete Broadcast
13774: case 0x09: // Windows Enhanced Mode Begin Exit Broadcast
13775: break;
13776: case 0x07:
13777: // Virtual Device Call API
13778: break;
1.1.1.22 root 13779: case 0x0a:
13780: if(!no_windows) {
13781: REG16(AX) = 0x0000;
1.1.1.30 root 13782: REG8(BH) = win_major_version;
13783: REG8(BL) = win_minor_version;
1.1.1.49 root 13784: // REG16(CX) = 0x0002; // standard
1.1.1.22 root 13785: REG16(CX) = 0x0003; // enhanced
13786: }
13787: break;
1.1.1.30 root 13788: case 0x0b:
13789: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 13790: case 0x0e:
13791: case 0x0f:
1.1.1.30 root 13792: case 0x10:
1.1.1.22 root 13793: case 0x11:
13794: case 0x12:
13795: case 0x13:
13796: case 0x14:
1.1.1.30 root 13797: case 0x15:
1.1.1.43 root 13798: case 0x81:
13799: case 0x82:
1.1.1.44 root 13800: case 0x84:
1.1.1.49 root 13801: case 0x85:
1.1.1.33 root 13802: case 0x86:
1.1.1.22 root 13803: case 0x87:
1.1.1.30 root 13804: case 0x89:
1.1.1.33 root 13805: case 0x8a:
1.1.1.22 root 13806: // function not supported, do not clear AX
13807: break;
1.1.1.14 root 13808: case 0x80:
13809: Sleep(10);
1.1.1.35 root 13810: REQUEST_HARDWRE_UPDATE();
1.1.1.29 root 13811: REG8(AL) = 0x00;
1.1.1.14 root 13812: break;
1.1.1.33 root 13813: case 0x83:
13814: REG16(BX) = 0x01; // system vm id
13815: break;
1.1.1.22 root 13816: case 0x8e:
13817: REG16(AX) = 0x00; // failed
13818: break;
1.1.1.20 root 13819: case 0x8f:
13820: switch(REG8(DH)) {
13821: case 0x01:
1.1.1.49 root 13822: // REG16(AX) = 0x0000; // close command selected but not yet acknowledged
13823: // REG16(AX) = 0x0001; // close command issued and acknowledged
13824: REG16(AX) = 0x168f; // close command not selected -- application should continue
13825: break;
13826: default:
13827: REG16(AX) = 0x0000; // successful
1.1.1.20 root 13828: break;
13829: }
13830: break;
1.1 root 13831: default:
1.1.1.22 root 13832: 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));
13833: REG16(AX) = 0x01;
13834: m_CF = 1;
13835: break;
13836: }
13837: }
13838:
13839: inline void msdos_int_2fh_19h()
13840: {
13841: switch(REG8(AL)) {
13842: case 0x00:
1.1.1.29 root 13843: // SHELLB.COM is not installed
13844: // REG8(AL) = 0x00;
1.1.1.22 root 13845: break;
13846: case 0x01:
13847: case 0x02:
13848: case 0x03:
13849: case 0x04:
13850: REG16(AX) = 0x01;
13851: m_CF = 1;
13852: break;
1.1.1.29 root 13853: case 0x80:
13854: // IBM ROM-DOS v4.0 is not installed
13855: // REG8(AL) = 0x00;
13856: break;
1.1.1.22 root 13857: default:
13858: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 13859: REG16(AX) = 0x01;
1.1.1.3 root 13860: m_CF = 1;
1.1 root 13861: break;
13862: }
13863: }
13864:
13865: inline void msdos_int_2fh_1ah()
13866: {
13867: switch(REG8(AL)) {
13868: case 0x00:
1.1.1.29 root 13869: // ANSI.SYS is installed
1.1 root 13870: REG8(AL) = 0xff;
13871: break;
1.1.1.49 root 13872: case 0x01:
1.1.1.50 root 13873: if(REG8(CL) == 0x5f) {
13874: // set display information
13875: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) >= 14) {
13876: int cur_width = *(UINT16 *)(mem + 0x44a) + 0;
13877: int cur_height = *(UINT8 *)(mem + 0x484) + 1;
13878: int new_width = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // character columns
13879: int new_height = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10); // character rows
13880:
13881: if(cur_width != new_width || cur_height != new_height) {
13882: pcbios_set_console_size(new_width, new_height, true);
13883: }
13884: }
13885: } else if(REG8(CL) == 0x7f) {
1.1.1.49 root 13886: // get display information
1.1.1.50 root 13887: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0; // level (0 for DOS 4.x-6.0)
13888: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0; // reserved (0)
13889: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14; // length of following data (14)
13890: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1; // bit 0 set for blink, clear for intensity
13891: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1; // mode type (1=text, 2=graphics)
13892: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0; // reserved (0)
13893: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4; // 4 bits per pixel
13894: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a) + 0); // pixel columns
13895: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1); // pixel rows
13896: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a) + 0; // character columns
13897: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1; // character rows
1.1.1.49 root 13898: } else {
13899: 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));
13900: REG16(AX) = 0x01;
13901: m_CF = 1;
13902: }
13903: break;
1.1 root 13904: default:
1.1.1.22 root 13905: 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));
13906: REG16(AX) = 0x01;
13907: m_CF = 1;
13908: break;
13909: }
13910: }
13911:
1.1.1.30 root 13912: inline void msdos_int_2fh_40h()
1.1.1.22 root 13913: {
13914: switch(REG8(AL)) {
13915: case 0x00:
1.1.1.30 root 13916: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
13917: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 13918: break;
1.1.1.43 root 13919: case 0x10:
13920: // OS/2 v2.0+ - Installation Check
13921: REG16(AX) = 0x01;
13922: m_CF = 1;
13923: break;
1.1.1.22 root 13924: default:
13925: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 13926: REG16(AX) = 0x01;
1.1.1.3 root 13927: m_CF = 1;
1.1 root 13928: break;
13929: }
13930: }
13931:
13932: inline void msdos_int_2fh_43h()
13933: {
13934: switch(REG8(AL)) {
13935: case 0x00:
1.1.1.29 root 13936: // XMS is installed ?
1.1.1.19 root 13937: #ifdef SUPPORT_XMS
13938: if(support_xms) {
13939: REG8(AL) = 0x80;
1.1.1.44 root 13940: }
13941: #endif
13942: break;
13943: case 0x08:
13944: #ifdef SUPPORT_XMS
13945: if(support_xms) {
13946: REG8(AL) = 0x43;
13947: REG8(BL) = 0x01; // IBM PC/AT
13948: REG8(BH) = 0x01; // Fast AT A20 switch time
13949: }
1.1.1.19 root 13950: #endif
13951: break;
13952: case 0x10:
13953: SREG(ES) = XMS_TOP >> 4;
13954: i386_load_segment_descriptor(ES);
1.1.1.26 root 13955: REG16(BX) = 0x15;
1.1 root 13956: break;
1.1.1.44 root 13957: case 0xe0:
13958: // DOS Protected Mode Services (DPMS) v1.0 is not installed
13959: if(REG16(BX) == 0x0000 && REG16(CX) == 0x4450 && REG16(DX) == 0x4d53) {
13960: break;
13961: }
1.1 root 13962: default:
1.1.1.22 root 13963: 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));
13964: REG16(AX) = 0x01;
13965: m_CF = 1;
13966: break;
13967: }
13968: }
13969:
13970: inline void msdos_int_2fh_46h()
13971: {
13972: switch(REG8(AL)) {
13973: case 0x80:
1.1.1.29 root 13974: // Windows v3.0 is not installed
13975: // REG8(AL) = 0x00;
1.1.1.22 root 13976: break;
13977: default:
13978: 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));
13979: REG16(AX) = 0x01;
13980: m_CF = 1;
13981: break;
13982: }
13983: }
13984:
13985: inline void msdos_int_2fh_48h()
13986: {
13987: switch(REG8(AL)) {
13988: case 0x00:
1.1.1.29 root 13989: // DOSKEY is not installed
13990: // REG8(AL) = 0x00;
1.1.1.22 root 13991: break;
13992: case 0x10:
13993: msdos_int_21h_0ah();
13994: REG16(AX) = 0x00;
13995: break;
13996: default:
13997: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 13998: REG16(AX) = 0x01;
1.1.1.3 root 13999: m_CF = 1;
1.1 root 14000: break;
14001: }
14002: }
14003:
14004: inline void msdos_int_2fh_4ah()
14005: {
14006: switch(REG8(AL)) {
1.1.1.29 root 14007: #ifdef SUPPORT_HMA
14008: case 0x01: // DOS 5.0+ - Query Free HMA Space
14009: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
14010: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14011: // restore first free mcb in high memory area
14012: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14013: }
14014: int offset = 0xffff;
14015: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
14016: REG16(DI) = offset + 0x10;
14017: } else {
14018: REG16(DI) = 0xffff;
14019: }
14020: } else {
14021: // HMA is already used
14022: REG16(BX) = 0;
14023: REG16(DI) = 0xffff;
14024: }
14025: SREG(ES) = 0xffff;
14026: i386_load_segment_descriptor(ES);
14027: break;
14028: case 0x02: // DOS 5.0+ - Allocate HMA Space
14029: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
14030: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14031: // restore first free mcb in high memory area
14032: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14033: }
14034: int size = REG16(BX), offset;
14035: if((size % 16) != 0) {
14036: size &= ~15;
14037: size += 16;
14038: }
14039: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
14040: REG16(BX) = size;
14041: REG16(DI) = offset + 0x10;
14042: is_hma_used_by_int_2fh = true;
14043: } else {
14044: REG16(BX) = 0;
14045: REG16(DI) = 0xffff;
14046: }
14047: } else {
14048: // HMA is already used
14049: REG16(BX) = 0;
14050: REG16(DI) = 0xffff;
14051: }
14052: SREG(ES) = 0xffff;
14053: i386_load_segment_descriptor(ES);
14054: break;
14055: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
14056: if(REG8(DL) == 0x00) {
14057: if(!is_hma_used_by_xms) {
14058: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14059: // restore first free mcb in high memory area
14060: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14061: is_hma_used_by_int_2fh = false;
14062: }
14063: int size = REG16(BX), offset;
14064: if((size % 16) != 0) {
14065: size &= ~15;
14066: size += 16;
14067: }
14068: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
14069: // REG16(BX) = size;
14070: SREG(ES) = 0xffff;
14071: i386_load_segment_descriptor(ES);
14072: REG16(DI) = offset + 0x10;
14073: is_hma_used_by_int_2fh = true;
14074: } else {
14075: REG16(DI) = 0xffff;
14076: }
14077: } else {
14078: REG16(DI) = 0xffff;
14079: }
14080: } else if(REG8(DL) == 0x01) {
14081: if(!is_hma_used_by_xms) {
14082: int size = REG16(BX);
14083: if((size % 16) != 0) {
14084: size &= ~15;
14085: size += 16;
14086: }
14087: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
14088: // memory block address is not changed
14089: } else {
14090: REG16(DI) = 0xffff;
14091: }
14092: } else {
14093: REG16(DI) = 0xffff;
14094: }
14095: } else if(REG8(DL) == 0x02) {
14096: if(!is_hma_used_by_xms) {
14097: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14098: // restore first free mcb in high memory area
14099: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14100: is_hma_used_by_int_2fh = false;
14101: } else {
14102: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
14103: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
14104: is_hma_used_by_int_2fh = false;
14105: }
14106: }
14107: }
14108: } else {
14109: 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));
14110: REG16(AX) = 0x01;
14111: m_CF = 1;
14112: }
14113: break;
14114: case 0x04: // Windows95 - Get Start of HMA Memory Chain
14115: if(!is_hma_used_by_xms) {
14116: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
14117: // restore first free mcb in high memory area
14118: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14119: is_hma_used_by_int_2fh = false;
14120: }
14121: REG16(AX) = 0x0000;
14122: SREG(ES) = 0xffff;
14123: i386_load_segment_descriptor(ES);
14124: REG16(DI) = 0x10;
14125: }
14126: break;
14127: #else
1.1 root 14128: case 0x01:
14129: case 0x02:
1.1.1.29 root 14130: // HMA is already used
1.1.1.27 root 14131: REG16(BX) = 0x0000;
1.1.1.3 root 14132: SREG(ES) = 0xffff;
14133: i386_load_segment_descriptor(ES);
1.1 root 14134: REG16(DI) = 0xffff;
14135: break;
1.1.1.19 root 14136: case 0x03:
14137: // unable to allocate
14138: REG16(DI) = 0xffff;
14139: break;
14140: case 0x04:
14141: // function not supported, do not clear AX
14142: break;
1.1.1.29 root 14143: #endif
14144: case 0x10:
1.1.1.42 root 14145: switch(REG16(BX)) {
14146: case 0x0000:
14147: case 0x0001:
14148: case 0x0002:
14149: case 0x0003:
14150: case 0x0004:
14151: case 0x0005:
14152: case 0x0006:
14153: case 0x0007:
14154: case 0x0008:
14155: case 0x000a:
14156: case 0x1234:
14157: // SMARTDRV v4.00+ is not installed
14158: break;
14159: default:
1.1.1.29 root 14160: 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));
14161: REG16(AX) = 0x01;
14162: m_CF = 1;
1.1.1.42 root 14163: break;
1.1.1.29 root 14164: }
14165: break;
14166: case 0x11:
1.1.1.42 root 14167: switch(REG16(BX)) {
14168: case 0x0000:
14169: case 0x0001:
14170: case 0x0002:
14171: case 0x0003:
14172: case 0x0004:
14173: case 0x0005:
14174: case 0x0006:
14175: case 0x0007:
14176: case 0x0008:
14177: case 0x0009:
14178: case 0x000a:
14179: case 0x000b:
14180: case 0xfffe:
14181: case 0xffff:
1.1.1.29 root 14182: // DBLSPACE.BIN is not installed
1.1.1.42 root 14183: break;
14184: default:
14185: 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));
14186: REG16(AX) = 0x01;
14187: m_CF = 1;
14188: break;
14189: }
14190: break;
14191: case 0x12:
14192: if(REG16(CX) == 0x4d52 && REG16(DX) == 0x4349) {
14193: // Microsoft Realtime Compression Interface (MRCI) is not installed
14194: } else if(REG16(CX) == 0x5354 && REG16(DX) == 0x4143) {
14195: // Stacker 4 LZS Compression Interface (LZSAPI) is not installed
1.1.1.29 root 14196: } else {
14197: 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));
14198: REG16(AX) = 0x01;
14199: m_CF = 1;
14200: }
1.1.1.22 root 14201: break;
1.1.1.42 root 14202: case 0x13:
14203: // DBLSPACE.BIN is not installed
14204: break;
1.1.1.22 root 14205: default:
14206: 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));
14207: REG16(AX) = 0x01;
14208: m_CF = 1;
14209: break;
14210: }
14211: }
14212:
14213: inline void msdos_int_2fh_4bh()
14214: {
14215: switch(REG8(AL)) {
1.1.1.24 root 14216: case 0x01:
1.1.1.22 root 14217: case 0x02:
1.1.1.29 root 14218: // Task Switcher is not installed
1.1.1.24 root 14219: break;
14220: case 0x03:
14221: // this call is available from within DOSSHELL even if the task switcher is not installed
14222: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 14223: break;
1.1.1.30 root 14224: case 0x04:
14225: REG16(BX) = 0x0000; // free switcher id successfully
14226: break;
1.1.1.43 root 14227: case 0x05:
14228: REG16(BX) = 0x0000; // no instance data chain
14229: SREG(ES) = 0x0000;
14230: i386_load_segment_descriptor(ES);
14231: break;
1.1 root 14232: default:
1.1.1.22 root 14233: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 14234: REG16(AX) = 0x01;
1.1.1.3 root 14235: m_CF = 1;
1.1 root 14236: break;
14237: }
14238: }
14239:
1.1.1.44 root 14240: inline void msdos_int_2fh_4dh()
14241: {
14242: switch(REG8(AL)) {
14243: case 0x00:
14244: // KKCFUNC is not installed ???
14245: break;
14246: default:
14247: // 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));
14248: REG16(AX) = 0x01; // invalid function
14249: m_CF = 1;
14250: break;
14251: }
14252: }
14253:
1.1 root 14254: inline void msdos_int_2fh_4fh()
14255: {
14256: switch(REG8(AL)) {
14257: case 0x00:
1.1.1.29 root 14258: // BILING is installed
1.1.1.27 root 14259: REG16(AX) = 0x0000;
14260: REG8(DL) = 0x01; // major version
14261: REG8(DH) = 0x00; // minor version
1.1 root 14262: break;
14263: case 0x01:
1.1.1.27 root 14264: REG16(AX) = 0x0000;
1.1 root 14265: REG16(BX) = active_code_page;
14266: break;
14267: default:
1.1.1.22 root 14268: 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));
14269: REG16(AX) = 0x01;
14270: m_CF = 1;
14271: break;
14272: }
14273: }
14274:
14275: inline void msdos_int_2fh_55h()
14276: {
14277: switch(REG8(AL)) {
14278: case 0x00:
14279: case 0x01:
14280: // 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));
14281: break;
14282: default:
14283: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 14284: REG16(AX) = 0x01;
1.1.1.3 root 14285: m_CF = 1;
1.1 root 14286: break;
14287: }
14288: }
14289:
1.1.1.44 root 14290: inline void msdos_int_2fh_56h()
14291: {
14292: switch(REG8(AL)) {
14293: case 0x00:
14294: // INTERLNK is not installed
14295: break;
14296: case 0x01:
14297: // this call is available from within SCANDISK even if INTERLNK is not installed
14298: // if(msdos_is_remote_drive(REG8(BH))) {
14299: // REG8(AL) = 0x00;
14300: // }
14301: break;
14302: default:
14303: 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));
14304: REG16(AX) = 0x01;
14305: m_CF = 1;
14306: break;
14307: }
14308: }
14309:
1.1.1.24 root 14310: inline void msdos_int_2fh_adh()
14311: {
14312: switch(REG8(AL)) {
14313: case 0x00:
1.1.1.29 root 14314: // DISPLAY.SYS is installed
1.1.1.24 root 14315: REG8(AL) = 0xff;
14316: REG16(BX) = 0x100; // ???
14317: break;
14318: case 0x01:
14319: active_code_page = REG16(BX);
14320: msdos_nls_tables_update();
14321: REG16(AX) = 0x01;
14322: break;
14323: case 0x02:
14324: REG16(BX) = active_code_page;
14325: break;
14326: case 0x03:
14327: // FIXME
14328: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
14329: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
14330: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
14331: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
14332: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
14333: break;
14334: case 0x80:
1.1.1.49 root 14335: // KEYB.COM is not installed
14336: break;
1.1.1.24 root 14337: default:
14338: 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));
14339: REG16(AX) = 0x01;
14340: m_CF = 1;
14341: break;
14342: }
14343: }
14344:
1.1 root 14345: inline void msdos_int_2fh_aeh()
14346: {
14347: switch(REG8(AL)) {
14348: case 0x00:
1.1.1.28 root 14349: // FIXME: we need to check the given command line
14350: REG8(AL) = 0x00; // the command should be executed as usual
14351: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 14352: break;
14353: case 0x01:
14354: {
14355: char command[MAX_PATH];
14356: memset(command, 0, sizeof(command));
1.1.1.3 root 14357: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 14358:
14359: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
14360: param->env_seg = 0;
14361: param->cmd_line.w.l = 44;
14362: param->cmd_line.w.h = (WORK_TOP >> 4);
14363: param->fcb1.w.l = 24;
14364: param->fcb1.w.h = (WORK_TOP >> 4);
14365: param->fcb2.w.l = 24;
14366: param->fcb2.w.h = (WORK_TOP >> 4);
14367:
14368: memset(mem + WORK_TOP + 24, 0x20, 20);
14369:
14370: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 14371: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
14372: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 14373: cmd_line->cmd[cmd_line->len] = 0x0d;
14374:
1.1.1.28 root 14375: try {
14376: msdos_process_exec(command, param, 0);
14377: } catch(...) {
14378: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 14379: }
14380: }
14381: break;
14382: default:
1.1.1.22 root 14383: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 14384: REG16(AX) = 0x01;
1.1.1.3 root 14385: m_CF = 1;
1.1 root 14386: break;
14387: }
14388: }
14389:
1.1.1.34 root 14390: inline void msdos_int_2fh_b7h()
14391: {
14392: switch(REG8(AL)) {
14393: case 0x00:
14394: // APPEND is not installed
14395: // REG8(AL) = 0x00;
14396: break;
1.1.1.44 root 14397: case 0x06:
14398: REG16(BX) = 0x0000;
14399: break;
1.1.1.34 root 14400: case 0x07:
1.1.1.43 root 14401: case 0x11:
1.1.1.34 root 14402: // COMMAND.COM calls this service without checking APPEND is installed
14403: break;
14404: default:
14405: 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));
14406: REG16(AX) = 0x01;
14407: m_CF = 1;
14408: break;
14409: }
14410: }
14411:
1.1.1.24 root 14412: inline void msdos_int_33h_0000h()
14413: {
14414: REG16(AX) = 0xffff; // hardware/driver installed
14415: REG16(BX) = MAX_MOUSE_BUTTONS;
14416: }
14417:
14418: inline void msdos_int_33h_0001h()
14419: {
1.1.1.34 root 14420: if(mouse.hidden > 0) {
14421: mouse.hidden--;
14422: }
14423: if(mouse.hidden == 0) {
1.1.1.24 root 14424: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
14425: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
14426: }
14427: pic[1].imr &= ~0x10; // enable irq12
14428: }
14429: }
14430:
14431: inline void msdos_int_33h_0002h()
14432: {
1.1.1.34 root 14433: mouse.hidden++;
14434: // SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode & ~ENABLE_MOUSE_INPUT);
14435: pic[1].imr |= 0x10; // enable irq12
1.1.1.24 root 14436: }
14437:
14438: inline void msdos_int_33h_0003h()
14439: {
1.1.1.34 root 14440: // if(mouse.hidden > 0) {
14441: update_console_input();
14442: // }
1.1.1.24 root 14443: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 14444: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
14445: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
14446: }
14447:
14448: inline void msdos_int_33h_0004h()
14449: {
14450: mouse.position.x = REG16(CX);
14451: mouse.position.x = REG16(DX);
1.1.1.24 root 14452: }
14453:
14454: inline void msdos_int_33h_0005h()
14455: {
1.1.1.34 root 14456: // if(mouse.hidden > 0) {
14457: update_console_input();
14458: // }
1.1.1.24 root 14459: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
14460: int idx = REG16(BX);
1.1.1.34 root 14461: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff);
14462: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x));
14463: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.buttons[idx].pressed_position.y));
1.1.1.24 root 14464: mouse.buttons[idx].pressed_times = 0;
14465: } else {
14466: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
14467: }
14468: REG16(AX) = mouse.get_buttons();
14469: }
14470:
14471: inline void msdos_int_33h_0006h()
14472: {
1.1.1.34 root 14473: // if(mouse.hidden > 0) {
14474: update_console_input();
14475: // }
1.1.1.24 root 14476: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
14477: int idx = REG16(BX);
1.1.1.34 root 14478: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff);
14479: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x));
14480: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.buttons[idx].released_position.y));
1.1.1.24 root 14481: mouse.buttons[idx].released_times = 0;
14482: } else {
14483: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
14484: }
14485: REG16(AX) = mouse.get_buttons();
14486: }
14487:
14488: inline void msdos_int_33h_0007h()
14489: {
14490: mouse.min_position.x = min(REG16(CX), REG16(DX));
14491: mouse.max_position.x = max(REG16(CX), REG16(DX));
14492: }
14493:
14494: inline void msdos_int_33h_0008h()
14495: {
14496: mouse.min_position.y = min(REG16(CX), REG16(DX));
14497: mouse.max_position.y = max(REG16(CX), REG16(DX));
14498: }
14499:
14500: inline void msdos_int_33h_0009h()
14501: {
14502: mouse.hot_spot[0] = REG16(BX);
14503: mouse.hot_spot[1] = REG16(CX);
14504: }
14505:
1.1.1.49 root 14506: inline void msdos_int_33h_000ah()
14507: {
14508: mouse.screen_mask = REG16(CX);
14509: mouse.cursor_mask = REG16(DX);
14510: }
14511:
1.1.1.24 root 14512: inline void msdos_int_33h_000bh()
14513: {
1.1.1.34 root 14514: // if(mouse.hidden > 0) {
14515: update_console_input();
14516: // }
1.1.1.24 root 14517: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
14518: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
14519: mouse.prev_position.x = mouse.position.x;
14520: mouse.prev_position.y = mouse.position.y;
14521: REG16(CX) = dx;
14522: REG16(DX) = dy;
14523: }
14524:
14525: inline void msdos_int_33h_000ch()
14526: {
14527: mouse.call_mask = REG16(CX);
14528: mouse.call_addr.w.l = REG16(DX);
14529: mouse.call_addr.w.h = SREG(ES);
14530: }
14531:
14532: inline void msdos_int_33h_000fh()
14533: {
14534: mouse.mickey.x = REG16(CX);
14535: mouse.mickey.y = REG16(DX);
14536: }
14537:
14538: inline void msdos_int_33h_0011h()
14539: {
14540: REG16(AX) = 0xffff;
14541: REG16(BX) = MAX_MOUSE_BUTTONS;
14542: }
14543:
14544: inline void msdos_int_33h_0014h()
14545: {
14546: UINT16 old_mask = mouse.call_mask;
14547: UINT16 old_ofs = mouse.call_addr.w.l;
14548: UINT16 old_seg = mouse.call_addr.w.h;
14549:
14550: mouse.call_mask = REG16(CX);
14551: mouse.call_addr.w.l = REG16(DX);
14552: mouse.call_addr.w.h = SREG(ES);
14553:
14554: REG16(CX) = old_mask;
14555: REG16(DX) = old_ofs;
14556: SREG(ES) = old_seg;
14557: i386_load_segment_descriptor(ES);
14558: }
14559:
14560: inline void msdos_int_33h_0015h()
14561: {
14562: REG16(BX) = sizeof(mouse);
14563: }
14564:
14565: inline void msdos_int_33h_0016h()
14566: {
14567: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
14568: }
14569:
14570: inline void msdos_int_33h_0017h()
14571: {
14572: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
14573: }
14574:
1.1.1.43 root 14575: inline void msdos_int_33h_0018h()
14576: {
14577: for(int i = 0; i < 8; i++) {
14578: if(REG16(CX) & (1 << i)) {
14579: if(mouse.call_addr_alt[i].dw && !(REG16(DX) == 0 && SREG(ES) == 0)) {
14580: // event handler already exists
14581: REG16(AX) = 0xffff;
14582: break;
14583: }
14584: mouse.call_addr_alt[i].w.l = REG16(DX);
14585: mouse.call_addr_alt[i].w.h = SREG(ES);
14586: }
14587: }
14588: }
14589:
14590: inline void msdos_int_33h_0019h()
14591: {
14592: UINT16 call_mask = REG16(CX);
14593:
14594: REG16(CX) = 0;
14595:
14596: for(int i = 0; i < 8; i++) {
14597: if((call_mask & (1 << i)) && mouse.call_addr_alt[i].dw) {
14598: for(int j = 0; j < 8; j++) {
14599: if((call_mask & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
14600: REG16(CX) |= (1 << j);
14601: }
14602: }
14603: REG16(DX) = mouse.call_addr_alt[i].w.l;
14604: REG16(BX) = mouse.call_addr_alt[i].w.h;
14605: break;
14606: }
14607: }
14608: }
14609:
1.1.1.24 root 14610: inline void msdos_int_33h_001ah()
14611: {
14612: mouse.sensitivity[0] = REG16(BX);
14613: mouse.sensitivity[1] = REG16(CX);
14614: mouse.sensitivity[2] = REG16(DX);
14615: }
14616:
14617: inline void msdos_int_33h_001bh()
14618: {
14619: REG16(BX) = mouse.sensitivity[0];
14620: REG16(CX) = mouse.sensitivity[1];
14621: REG16(DX) = mouse.sensitivity[2];
14622: }
14623:
14624: inline void msdos_int_33h_001dh()
14625: {
14626: mouse.display_page = REG16(BX);
14627: }
14628:
14629: inline void msdos_int_33h_001eh()
14630: {
14631: REG16(BX) = mouse.display_page;
14632: }
14633:
1.1.1.34 root 14634: inline void msdos_int_33h_001fh()
14635: {
14636: // from DOSBox
14637: REG16(BX) = 0x0000;
14638: SREG(ES) = 0x0000;
14639: i386_load_segment_descriptor(ES);
14640: mouse.enabled = false;
14641: mouse.old_hidden = mouse.hidden;
14642: mouse.hidden = 1;
14643: }
14644:
14645: inline void msdos_int_33h_0020h()
14646: {
14647: // from DOSBox
14648: mouse.enabled = true;
14649: mouse.hidden = mouse.old_hidden;
14650: }
14651:
1.1.1.24 root 14652: inline void msdos_int_33h_0021h()
14653: {
14654: REG16(AX) = 0xffff;
14655: REG16(BX) = MAX_MOUSE_BUTTONS;
14656: }
14657:
14658: inline void msdos_int_33h_0022h()
14659: {
14660: mouse.language = REG16(BX);
14661: }
14662:
14663: inline void msdos_int_33h_0023h()
14664: {
14665: REG16(BX) = mouse.language;
14666: }
14667:
14668: inline void msdos_int_33h_0024h()
14669: {
14670: REG16(BX) = 0x0805; // V8.05
14671: REG16(CX) = 0x0400; // PS/2
14672: }
14673:
1.1.1.49 root 14674: inline void msdos_int_33h_0025h()
14675: {
14676: REG16(AX) = 0x8000; // driver (not TSR), software text cursor
14677: }
14678:
1.1.1.24 root 14679: inline void msdos_int_33h_0026h()
14680: {
14681: REG16(BX) = 0x0000;
14682: REG16(CX) = mouse.max_position.x;
14683: REG16(DX) = mouse.max_position.y;
14684: }
14685:
1.1.1.49 root 14686: inline void msdos_int_33h_0027h()
14687: {
14688: // if(mouse.hidden > 0) {
14689: update_console_input();
14690: // }
14691: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
14692: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
14693: mouse.prev_position.x = mouse.position.x;
14694: mouse.prev_position.y = mouse.position.y;
14695: REG16(AX) = mouse.screen_mask;
14696: REG16(BX) = mouse.cursor_mask;
14697: REG16(CX) = dx;
14698: REG16(DX) = dy;
14699: }
14700:
14701: inline void msdos_int_33h_0028h()
14702: {
14703: if(REG16(CX) != 0) {
14704: UINT8 tmp = REG8(AL);
14705: REG8(AL) = REG8(CL);
14706: pcbios_int_10h_00h();
14707: REG8(AL) = tmp;
14708: }
14709: REG8(CL) = 0x00; // successful
14710: }
14711:
14712: inline void msdos_int_33h_0029h()
14713: {
14714: switch(REG16(CX)) {
14715: case 0x0000:
14716: REG16(CX) = 0x0003;
14717: sprintf((char *)(mem + WORK_TOP), "TEXT Mode (80x25)$");
14718: break;
14719: case 0x0003:
14720: REG16(CX) = 0x0070;
14721: sprintf((char *)(mem + WORK_TOP), "V-TEXT Mode (%dx%d)$", scr_width, scr_height);
14722: break;
14723: case 0x0070:
14724: REG16(CX) = 0x0071;
14725: sprintf((char *)(mem + WORK_TOP), "Extended CGA V-TEXT Mode (%dx%d)$", scr_width, scr_height);
14726: break;
14727: case 0x0071:
14728: REG16(CX) = 0x0073;
14729: sprintf((char *)(mem + WORK_TOP), "Extended CGA TEXT Mode (80x25)$");
14730: break;
14731: default:
14732: REG16(CX) = 0x0000;
14733: break;
14734: }
14735: if(REG16(CX) != 0) {
14736: SREG(DS) = (WORK_TOP >> 4);
14737: } else {
14738: SREG(DS) = 0x0000;
14739: }
14740: i386_load_segment_descriptor(DS);
14741: REG16(DX) = 0x0000;
14742: }
14743:
1.1.1.24 root 14744: inline void msdos_int_33h_002ah()
14745: {
1.1.1.34 root 14746: REG16(AX) = -mouse.hidden;
1.1.1.24 root 14747: REG16(BX) = mouse.hot_spot[0];
14748: REG16(CX) = mouse.hot_spot[1];
14749: REG16(DX) = 4; // PS/2
14750: }
14751:
14752: inline void msdos_int_33h_0031h()
14753: {
14754: REG16(AX) = mouse.min_position.x;
14755: REG16(BX) = mouse.min_position.y;
14756: REG16(CX) = mouse.max_position.x;
14757: REG16(DX) = mouse.max_position.y;
14758: }
14759:
14760: inline void msdos_int_33h_0032h()
14761: {
14762: REG16(AX) = 0;
1.1.1.49 root 14763: REG16(AX) |= 0x8000; // 0025h
1.1.1.24 root 14764: REG16(AX) |= 0x4000; // 0026h
1.1.1.49 root 14765: REG16(AX) |= 0x2000; // 0027h
1.1.1.24 root 14766: // REG16(AX) |= 0x1000; // 0028h
14767: // REG16(AX) |= 0x0800; // 0029h
14768: REG16(AX) |= 0x0400; // 002ah
14769: // REG16(AX) |= 0x0200; // 002bh
14770: // REG16(AX) |= 0x0100; // 002ch
14771: // REG16(AX) |= 0x0080; // 002dh
14772: // REG16(AX) |= 0x0040; // 002eh
14773: REG16(AX) |= 0x0020; // 002fh
14774: // REG16(AX) |= 0x0010; // 0030h
14775: REG16(AX) |= 0x0008; // 0031h
14776: REG16(AX) |= 0x0004; // 0032h
14777: // REG16(AX) |= 0x0002; // 0033h
14778: // REG16(AX) |= 0x0001; // 0034h
14779: }
14780:
1.1.1.49 root 14781: inline void msdos_int_33h_004dh()
14782: {
14783: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), "Copyright 2017 MS-DOS Player");
14784: }
14785:
14786: inline void msdos_int_33h_006dh()
14787: {
14788: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x08; // V8.05
14789: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = 0x05;
14790: }
14791:
1.1.1.19 root 14792: inline void msdos_int_67h_40h()
14793: {
14794: if(!support_ems) {
14795: REG8(AH) = 0x84;
14796: } else {
14797: REG8(AH) = 0x00;
14798: }
14799: }
14800:
14801: inline void msdos_int_67h_41h()
14802: {
14803: if(!support_ems) {
14804: REG8(AH) = 0x84;
14805: } else {
14806: REG8(AH) = 0x00;
14807: REG16(BX) = EMS_TOP >> 4;
14808: }
14809: }
14810:
14811: inline void msdos_int_67h_42h()
14812: {
14813: if(!support_ems) {
14814: REG8(AH) = 0x84;
14815: } else {
14816: REG8(AH) = 0x00;
14817: REG16(BX) = free_ems_pages;
14818: REG16(DX) = MAX_EMS_PAGES;
14819: }
14820: }
14821:
14822: inline void msdos_int_67h_43h()
14823: {
14824: if(!support_ems) {
14825: REG8(AH) = 0x84;
14826: } else if(REG16(BX) > MAX_EMS_PAGES) {
14827: REG8(AH) = 0x87;
14828: } else if(REG16(BX) > free_ems_pages) {
14829: REG8(AH) = 0x88;
14830: } else if(REG16(BX) == 0) {
14831: REG8(AH) = 0x89;
14832: } else {
1.1.1.31 root 14833: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14834: if(!ems_handles[i].allocated) {
14835: ems_allocate_pages(i, REG16(BX));
14836: REG8(AH) = 0x00;
14837: REG16(DX) = i;
14838: return;
14839: }
14840: }
14841: REG8(AH) = 0x85;
14842: }
14843: }
14844:
14845: inline void msdos_int_67h_44h()
14846: {
14847: if(!support_ems) {
14848: REG8(AH) = 0x84;
1.1.1.31 root 14849: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14850: REG8(AH) = 0x83;
14851: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
14852: REG8(AH) = 0x8a;
14853: // } else if(!(REG8(AL) < 4)) {
14854: // REG8(AH) = 0x8b;
14855: } else if(REG16(BX) == 0xffff) {
14856: ems_unmap_page(REG8(AL) & 3);
14857: REG8(AH) = 0x00;
14858: } else {
14859: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
14860: REG8(AH) = 0x00;
14861: }
14862: }
14863:
14864: inline void msdos_int_67h_45h()
14865: {
14866: if(!support_ems) {
14867: REG8(AH) = 0x84;
1.1.1.31 root 14868: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14869: REG8(AH) = 0x83;
14870: } else {
14871: ems_release_pages(REG16(DX));
14872: REG8(AH) = 0x00;
14873: }
14874: }
14875:
14876: inline void msdos_int_67h_46h()
14877: {
14878: if(!support_ems) {
14879: REG8(AH) = 0x84;
14880: } else {
1.1.1.29 root 14881: // REG16(AX) = 0x0032; // EMS 3.2
14882: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 14883: }
14884: }
14885:
14886: inline void msdos_int_67h_47h()
14887: {
14888: // NOTE: the map data should be stored in the specified ems page, not process data
14889: process_t *process = msdos_process_info_get(current_psp);
14890:
14891: if(!support_ems) {
14892: REG8(AH) = 0x84;
1.1.1.31 root 14893: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14894: // REG8(AH) = 0x83;
14895: } else if(process->ems_pages_stored) {
14896: REG8(AH) = 0x8d;
14897: } else {
14898: for(int i = 0; i < 4; i++) {
14899: process->ems_pages[i].handle = ems_pages[i].handle;
14900: process->ems_pages[i].page = ems_pages[i].page;
14901: process->ems_pages[i].mapped = ems_pages[i].mapped;
14902: }
14903: process->ems_pages_stored = true;
14904: REG8(AH) = 0x00;
14905: }
14906: }
14907:
14908: inline void msdos_int_67h_48h()
14909: {
14910: // NOTE: the map data should be restored from the specified ems page, not process data
14911: process_t *process = msdos_process_info_get(current_psp);
14912:
14913: if(!support_ems) {
14914: REG8(AH) = 0x84;
1.1.1.31 root 14915: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14916: // REG8(AH) = 0x83;
14917: } else if(!process->ems_pages_stored) {
14918: REG8(AH) = 0x8e;
14919: } else {
14920: for(int i = 0; i < 4; i++) {
14921: if(process->ems_pages[i].mapped) {
14922: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
14923: } else {
14924: ems_unmap_page(i);
14925: }
14926: }
14927: process->ems_pages_stored = false;
14928: REG8(AH) = 0x00;
14929: }
14930: }
14931:
14932: inline void msdos_int_67h_4bh()
14933: {
14934: if(!support_ems) {
14935: REG8(AH) = 0x84;
14936: } else {
14937: REG8(AH) = 0x00;
14938: REG16(BX) = 0;
1.1.1.31 root 14939: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14940: if(ems_handles[i].allocated) {
14941: REG16(BX)++;
14942: }
14943: }
14944: }
14945: }
14946:
14947: inline void msdos_int_67h_4ch()
14948: {
14949: if(!support_ems) {
14950: REG8(AH) = 0x84;
1.1.1.31 root 14951: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14952: REG8(AH) = 0x83;
14953: } else {
14954: REG8(AH) = 0x00;
14955: REG16(BX) = ems_handles[REG16(DX)].pages;
14956: }
14957: }
14958:
14959: inline void msdos_int_67h_4dh()
14960: {
14961: if(!support_ems) {
14962: REG8(AH) = 0x84;
14963: } else {
14964: REG8(AH) = 0x00;
14965: REG16(BX) = 0;
1.1.1.31 root 14966: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14967: if(ems_handles[i].allocated) {
14968: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
14969: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
14970: REG16(BX)++;
14971: }
14972: }
14973: }
14974: }
14975:
1.1.1.20 root 14976: inline void msdos_int_67h_4eh()
14977: {
14978: if(!support_ems) {
14979: REG8(AH) = 0x84;
14980: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
14981: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
14982: // save page map
14983: for(int i = 0; i < 4; i++) {
14984: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
14985: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
14986: }
14987: }
14988: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
14989: // restore page map
14990: for(int i = 0; i < 4; i++) {
14991: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
14992: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
14993:
1.1.1.31 root 14994: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 14995: ems_map_page(i, handle, page);
14996: } else {
14997: ems_unmap_page(i);
14998: }
14999: }
15000: }
15001: REG8(AH) = 0x00;
15002: } else if(REG8(AL) == 0x03) {
15003: REG8(AH) = 0x00;
1.1.1.21 root 15004: REG8(AL) = 4 * 4;
15005: } else {
1.1.1.22 root 15006: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.21 root 15007: REG8(AH) = 0x8f;
15008: }
15009: }
15010:
15011: inline void msdos_int_67h_4fh()
15012: {
15013: if(!support_ems) {
15014: REG8(AH) = 0x84;
15015: } else if(REG8(AL) == 0x00) {
15016: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
15017:
15018: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
15019: for(int i = 0; i < count; i++) {
15020: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
15021: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
15022:
15023: // if(!(physical < 4)) {
15024: // REG8(AH) = 0x8b;
15025: // return;
15026: // }
15027: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
1.1.1.41 root 15028: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].handle : 0xffff;
15029: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
1.1.1.21 root 15030: }
15031: REG8(AH) = 0x00;
15032: } else if(REG8(AL) == 0x01) {
15033: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
15034:
15035: for(int i = 0; i < count; i++) {
15036: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
15037: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
15038: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
15039: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
15040:
15041: // if(!(physical < 4)) {
15042: // REG8(AH) = 0x8b;
15043: // return;
15044: // } else
1.1.1.41 root 15045: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && logical < ems_handles[handle].pages) {
1.1.1.21 root 15046: ems_map_page(physical & 3, handle, logical);
15047: } else {
1.1.1.41 root 15048: ems_unmap_page(physical & 3);
1.1.1.21 root 15049: }
15050: }
15051: REG8(AH) = 0x00;
15052: } else if(REG8(AL) == 0x02) {
15053: REG8(AH) = 0x00;
15054: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 15055: } else {
1.1.1.22 root 15056: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15057: REG8(AH) = 0x8f;
15058: }
15059: }
15060:
15061: inline void msdos_int_67h_50h()
15062: {
15063: if(!support_ems) {
15064: REG8(AH) = 0x84;
1.1.1.31 root 15065: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 15066: REG8(AH) = 0x83;
15067: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
15068: for(int i = 0; i < REG16(CX); i++) {
15069: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
15070: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
15071:
15072: if(REG8(AL) == 0x01) {
15073: physical = ((physical << 4) - EMS_TOP) / 0x4000;
15074: }
15075: // if(!(physical < 4)) {
15076: // REG8(AH) = 0x8b;
15077: // return;
15078: // } else
15079: if(logical == 0xffff) {
15080: ems_unmap_page(physical & 3);
15081: } else if(logical < ems_handles[REG16(DX)].pages) {
15082: ems_map_page(physical & 3, REG16(DX), logical);
15083: } else {
15084: REG8(AH) = 0x8a;
15085: return;
15086: }
15087: }
15088: REG8(AH) = 0x00;
15089: } else {
1.1.1.22 root 15090: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15091: REG8(AH) = 0x8f;
15092: }
15093: }
15094:
1.1.1.19 root 15095: inline void msdos_int_67h_51h()
15096: {
15097: if(!support_ems) {
15098: REG8(AH) = 0x84;
1.1.1.31 root 15099: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 15100: REG8(AH) = 0x83;
15101: } else if(REG16(BX) > MAX_EMS_PAGES) {
15102: REG8(AH) = 0x87;
15103: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
15104: REG8(AH) = 0x88;
15105: } else {
15106: ems_reallocate_pages(REG16(DX), REG16(BX));
15107: REG8(AH) = 0x00;
15108: }
15109: }
15110:
1.1.1.20 root 15111: inline void msdos_int_67h_52h()
15112: {
15113: if(!support_ems) {
15114: REG8(AH) = 0x84;
1.1.1.31 root 15115: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15116: // REG8(AH) = 0x83;
1.1.1.20 root 15117: } else if(REG8(AL) == 0x00) {
15118: REG8(AL) = 0x00; // handle is volatile
15119: REG8(AH) = 0x00;
15120: } else if(REG8(AL) == 0x01) {
15121: if(REG8(BL) == 0x00) {
15122: REG8(AH) = 0x00;
15123: } else {
15124: REG8(AH) = 0x90; // undefined attribute type
15125: }
15126: } else if(REG8(AL) == 0x02) {
15127: REG8(AL) = 0x00; // only volatile handles supported
15128: REG8(AH) = 0x00;
15129: } else {
1.1.1.22 root 15130: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15131: REG8(AH) = 0x8f;
15132: }
15133: }
15134:
1.1.1.19 root 15135: inline void msdos_int_67h_53h()
15136: {
15137: if(!support_ems) {
15138: REG8(AH) = 0x84;
1.1.1.31 root 15139: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 15140: REG8(AH) = 0x83;
15141: } else if(REG8(AL) == 0x00) {
15142: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
15143: REG8(AH) = 0x00;
15144: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 15145: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 15146: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
15147: REG8(AH) = 0xa1;
15148: return;
15149: }
15150: }
15151: REG8(AH) = 0x00;
15152: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
15153: } else {
1.1.1.22 root 15154: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15155: REG8(AH) = 0x8f;
1.1.1.19 root 15156: }
15157: }
15158:
15159: inline void msdos_int_67h_54h()
15160: {
15161: if(!support_ems) {
15162: REG8(AH) = 0x84;
15163: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 15164: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 15165: if(ems_handles[i].allocated) {
15166: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
15167: } else {
15168: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
15169: }
15170: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
15171: }
15172: REG8(AH) = 0x00;
15173: REG8(AL) = MAX_EMS_HANDLES;
15174: } else if(REG8(AL) == 0x01) {
15175: REG8(AH) = 0xa0; // not found
1.1.1.31 root 15176: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 15177: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
15178: REG8(AH) = 0x00;
15179: REG16(DX) = i;
15180: break;
15181: }
15182: }
15183: } else if(REG8(AL) == 0x02) {
15184: REG8(AH) = 0x00;
15185: REG16(BX) = MAX_EMS_HANDLES;
15186: } else {
1.1.1.22 root 15187: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15188: REG8(AH) = 0x8f;
15189: }
15190: }
15191:
1.1.1.49 root 15192: inline void msdos_int_67h_55h()
15193: {
15194: if(!support_ems) {
15195: REG8(AH) = 0x84;
15196: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15197: REG8(AH) = 0x83;
15198: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
15199: UINT16 jump_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0);
15200: UINT16 jump_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2);
15201: UINT8 entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4);
15202: UINT16 map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
15203: UINT16 map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7);
15204:
15205: for(int i = 0; i < (int)entries; i++) {
15206: int logical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 0);
15207: int physical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 2);
15208:
15209: if(REG8(AL) == 0x01) {
15210: physical = ((physical << 4) - EMS_TOP) / 0x4000;
15211: }
15212: // if(!(physical < 4)) {
15213: // REG8(AH) = 0x8b;
15214: // return;
15215: // } else
15216: if(logical == 0xffff) {
15217: ems_unmap_page(physical & 3);
15218: } else if(logical < ems_handles[REG16(DX)].pages) {
15219: ems_map_page(physical & 3, REG16(DX), logical);
15220: } else {
15221: REG8(AH) = 0x8a;
15222: return;
15223: }
15224: }
15225: i386_jmp_far(jump_seg, jump_ofs);
15226: REG8(AH) = 0x00;
15227: } else {
15228: 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));
15229: REG8(AH) = 0x8f;
15230: }
15231: }
15232:
15233: inline void msdos_int_67h_56h()
15234: {
15235: if(!support_ems) {
15236: REG8(AH) = 0x84;
15237: } else if(REG8(AL) == 0x02) {
15238: REG16(BX) = (2 + 2) * 4;
15239: REG8(AH) = 0x00;
15240: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
15241: REG8(AH) = 0x83;
15242: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
15243: UINT16 call_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0);
15244: UINT16 call_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2);
15245: UINT8 new_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4);
15246: UINT16 new_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
15247: UINT16 new_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7);
15248: #if 0
15249: UINT8 old_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 9);
15250: UINT16 old_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 10);
15251: UINT16 old_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 12);
15252: #endif
15253: UINT16 handles[4], pages[4];
15254:
15255: // alter page map and call routine is at fffc:001f
15256: if(!(call_seg == 0 && call_ofs == 0)) {
15257: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far
15258: mem[DUMMY_TOP + 0x20] = (call_ofs >> 0) & 0xff;
15259: mem[DUMMY_TOP + 0x21] = (call_ofs >> 8) & 0xff;
15260: mem[DUMMY_TOP + 0x22] = (call_seg >> 0) & 0xff;
15261: mem[DUMMY_TOP + 0x23] = (call_seg >> 8) & 0xff;
15262: } else {
15263: // invalid call addr :-(
15264: mem[DUMMY_TOP + 0x1f] = 0x90; // nop
15265: mem[DUMMY_TOP + 0x20] = 0x90; // nop
15266: mem[DUMMY_TOP + 0x21] = 0x90; // nop
15267: mem[DUMMY_TOP + 0x22] = 0x90; // nop
15268: mem[DUMMY_TOP + 0x23] = 0x90; // nop
15269: }
15270: // do call far (push cs/ip) in old mapping
15271: i386_call_far(DUMMY_TOP >> 4, 0x001f);
15272:
15273: // get old mapping data
15274: #if 0
15275: for(int i = 0; i < (int)old_entries; i++) {
15276: int logical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 0);
15277: int physical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 2);
15278:
15279: if(REG8(AL) == 0x01) {
15280: physical = ((physical << 4) - EMS_TOP) / 0x4000;
15281: }
15282: // if(!(physical < 4)) {
15283: // REG8(AH) = 0x8b;
15284: // return;
15285: // } else
15286: if(logical == 0xffff) {
15287: ems_unmap_page(physical & 3);
15288: } else if(logical < ems_handles[REG16(DX)].pages) {
15289: ems_map_page(physical & 3, REG16(DX), logical);
15290: } else {
15291: REG8(AH) = 0x8a;
15292: return;
15293: }
15294: }
15295: #endif
15296: for(int i = 0; i < 4; i++) {
15297: handles[i] = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
15298: pages [i] = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
15299: }
15300:
15301: // set new mapping
15302: for(int i = 0; i < (int)new_entries; i++) {
15303: int logical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 0);
15304: int physical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 2);
15305:
15306: if(REG8(AL) == 0x01) {
15307: physical = ((physical << 4) - EMS_TOP) / 0x4000;
15308: }
15309: // if(!(physical < 4)) {
15310: // REG8(AH) = 0x8b;
15311: // return;
15312: // } else
15313: if(logical == 0xffff) {
15314: ems_unmap_page(physical & 3);
15315: } else if(logical < ems_handles[REG16(DX)].pages) {
15316: ems_map_page(physical & 3, REG16(DX), logical);
15317: } else {
15318: REG8(AH) = 0x8a;
15319: return;
15320: }
15321: }
15322:
15323: // push old mapping data in new mapping
15324: for(int i = 0; i < 4; i++) {
15325: i386_push16(handles[i]);
15326: i386_push16(pages [i]);
15327: }
15328: REG8(AH) = 0x00;
15329: } else {
15330: 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));
15331: REG8(AH) = 0x8f;
15332: }
15333: }
15334:
1.1.1.20 root 15335: inline void msdos_int_67h_57h_tmp()
15336: {
15337: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
15338: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
15339: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
15340: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
15341: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
15342: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
15343: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
15344: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
15345: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
15346:
1.1.1.32 root 15347: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 15348: UINT32 src_addr, dest_addr;
15349: UINT32 src_addr_max, dest_addr_max;
15350:
15351: if(src_type == 0) {
15352: src_buffer = mem;
15353: src_addr = (src_seg << 4) + src_ofs;
15354: src_addr_max = MAX_MEM;
15355: } else {
1.1.1.31 root 15356: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 15357: REG8(AH) = 0x83;
15358: return;
15359: } else if(!(src_seg < ems_handles[src_handle].pages)) {
15360: REG8(AH) = 0x8a;
15361: return;
15362: }
1.1.1.32 root 15363: if(ems_handles[src_handle].buffer != NULL) {
15364: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
15365: }
1.1.1.20 root 15366: src_addr = src_ofs;
1.1.1.32 root 15367: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 15368: }
15369: if(dest_type == 0) {
15370: dest_buffer = mem;
15371: dest_addr = (dest_seg << 4) + dest_ofs;
15372: dest_addr_max = MAX_MEM;
15373: } else {
1.1.1.31 root 15374: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 15375: REG8(AH) = 0x83;
15376: return;
15377: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
15378: REG8(AH) = 0x8a;
15379: return;
15380: }
1.1.1.32 root 15381: if(ems_handles[dest_handle].buffer != NULL) {
15382: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
15383: }
1.1.1.20 root 15384: dest_addr = dest_ofs;
1.1.1.32 root 15385: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 15386: }
1.1.1.32 root 15387: if(src_buffer != NULL && dest_buffer != NULL) {
15388: for(int i = 0; i < copy_length; i++) {
15389: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
15390: if(REG8(AL) == 0x00) {
15391: dest_buffer[dest_addr++] = src_buffer[src_addr++];
15392: } else if(REG8(AL) == 0x01) {
15393: UINT8 tmp = dest_buffer[dest_addr];
15394: dest_buffer[dest_addr++] = src_buffer[src_addr];
15395: src_buffer[src_addr++] = tmp;
15396: }
15397: } else {
15398: REG8(AH) = 0x93;
15399: return;
1.1.1.20 root 15400: }
15401: }
1.1.1.32 root 15402: REG8(AH) = 0x00;
15403: } else {
15404: REG8(AH) = 0x80;
1.1.1.20 root 15405: }
15406: }
15407:
15408: inline void msdos_int_67h_57h()
15409: {
15410: if(!support_ems) {
15411: REG8(AH) = 0x84;
15412: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
15413: struct {
15414: UINT16 handle;
15415: UINT16 page;
15416: bool mapped;
15417: } tmp_pages[4];
15418:
15419: // unmap pages to copy memory data to ems buffer
15420: for(int i = 0; i < 4; i++) {
15421: tmp_pages[i].handle = ems_pages[i].handle;
15422: tmp_pages[i].page = ems_pages[i].page;
15423: tmp_pages[i].mapped = ems_pages[i].mapped;
15424: ems_unmap_page(i);
15425: }
15426:
15427: // run move/exchange operation
15428: msdos_int_67h_57h_tmp();
15429:
15430: // restore unmapped pages
15431: for(int i = 0; i < 4; i++) {
15432: if(tmp_pages[i].mapped) {
15433: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
15434: }
15435: }
15436: } else {
1.1.1.22 root 15437: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15438: REG8(AH) = 0x8f;
15439: }
15440: }
15441:
15442: inline void msdos_int_67h_58h()
15443: {
15444: if(!support_ems) {
15445: REG8(AH) = 0x84;
15446: } else if(REG8(AL) == 0x00) {
15447: for(int i = 0; i < 4; i++) {
1.1.1.30 root 15448: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
15449: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 15450: }
15451: REG8(AH) = 0x00;
15452: REG16(CX) = 4;
15453: } else if(REG8(AL) == 0x01) {
15454: REG8(AH) = 0x00;
15455: REG16(CX) = 4;
15456: } else {
1.1.1.22 root 15457: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15458: REG8(AH) = 0x8f;
15459: }
15460: }
15461:
1.1.1.42 root 15462: inline void msdos_int_67h_59h()
15463: {
15464: if(!support_ems) {
15465: REG8(AH) = 0x84;
15466: } else if(REG8(AL) == 0x00) {
1.1.1.49 root 15467: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1024;
15468: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 0;
15469: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 4 * 4;
15470: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = 0;
15471: REG8(AH) = 0x00;
15472: // REG8(AH) = 0xa4; // access denied by operating system
1.1.1.42 root 15473: } else if(REG8(AL) == 0x01) {
15474: REG8(AH) = 0x00;
15475: REG16(BX) = free_ems_pages;
15476: REG16(DX) = MAX_EMS_PAGES;
15477: } else {
15478: 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));
15479: REG8(AH) = 0x8f;
15480: }
15481: }
15482:
1.1.1.20 root 15483: inline void msdos_int_67h_5ah()
15484: {
15485: if(!support_ems) {
1.1.1.19 root 15486: REG8(AH) = 0x84;
1.1.1.20 root 15487: } else if(REG16(BX) > MAX_EMS_PAGES) {
15488: REG8(AH) = 0x87;
15489: } else if(REG16(BX) > free_ems_pages) {
15490: REG8(AH) = 0x88;
15491: // } else if(REG16(BX) == 0) {
15492: // REG8(AH) = 0x89;
15493: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 15494: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 15495: if(!ems_handles[i].allocated) {
15496: ems_allocate_pages(i, REG16(BX));
15497: REG8(AH) = 0x00;
15498: REG16(DX) = i;
15499: return;
15500: }
15501: }
15502: REG8(AH) = 0x85;
15503: } else {
1.1.1.22 root 15504: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 15505: REG8(AH) = 0x8f;
1.1.1.19 root 15506: }
15507: }
15508:
1.1.1.49 root 15509: inline void msdos_int_67h_5bh()
15510: {
15511: static UINT8 stored_bl = 0x00;
15512: static UINT16 stored_es = 0x0000;
15513: static UINT16 stored_di = 0x0000;
15514:
15515: if(!support_ems) {
15516: REG8(AH) = 0x84;
15517: } else if(REG8(AL) == 0x00) {
15518: if(stored_bl == 0x00) {
15519: if(!(stored_es == 0 && stored_di == 0)) {
15520: for(int i = 0; i < 4; i++) {
15521: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
15522: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
15523: }
15524: }
15525: SREG(ES) = stored_es;
15526: i386_load_segment_descriptor(ES);
15527: REG16(DI) = stored_di;
15528: } else {
15529: REG8(BL) = stored_bl;
15530: }
15531: REG8(AH) = 0x00;
15532: } else if(REG8(AL) == 0x01) {
15533: if(REG8(BL) == 0x00) {
15534: if(!(SREG(ES) == 0 && REG16(DI) == 0)) {
15535: for(int i = 0; i < 4; i++) {
15536: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0);
15537: UINT16 page = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2);
15538:
15539: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
15540: ems_map_page(i, handle, page);
15541: } else {
15542: ems_unmap_page(i);
15543: }
15544: }
15545: }
15546: }
15547: stored_bl = REG8(BL);
15548: stored_es = SREG(ES);
15549: stored_di = REG16(DI);
15550: REG8(AH) = 0x00;
15551: } else if(REG8(AL) == 0x02) {
15552: REG16(DX) = 4 * 4;
15553: REG8(AH) = 0x00;
15554: } else if(REG8(AL) == 0x03) {
15555: REG8(BL) = 0x00; // not supported
15556: REG8(AH) = 0x00;
15557: } else if(REG8(AL) == 0x04) {
15558: REG8(AH) = 0x00;
15559: } else if(REG8(AL) == 0x05) {
15560: REG8(BL) = 0x00; // not supported
15561: REG8(AH) = 0x00;
15562: } else {
15563: 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));
15564: REG8(AH) = 0x8f;
15565: }
15566: }
15567:
1.1.1.43 root 15568: inline void msdos_int_67h_5dh()
15569: {
15570: if(!support_ems) {
15571: REG8(AH) = 0x84;
15572: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
15573: REG8(AH) = 0xa4; // operating system denied access
15574: } else {
15575: 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));
15576: REG8(AH) = 0x8f;
15577: }
15578: }
15579:
1.1.1.49 root 15580: inline void msdos_int_67h_70h()
15581: {
15582: if(!support_ems) {
15583: REG8(AH) = 0x84;
15584: } else if(REG8(AL) == 0x00) {
15585: REG8(AL) = 0x00;
15586: REG8(AH) = 0x00;
15587: } else if(REG8(AL) == 0x01) {
15588: REG8(AL) = 0x00;
15589: // REG8(AH) = (REG8(BL) == 0x00) ? 0x00 : 0x80;
15590: REG8(AH) = 0x00;
15591: } else {
15592: 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));
15593: REG8(AH) = 0x8f;
15594: }
15595: }
15596:
1.1.1.30 root 15597: inline void msdos_int_67h_deh()
15598: {
15599: REG8(AH) = 0x84;
15600: }
15601:
1.1.1.19 root 15602: #ifdef SUPPORT_XMS
15603:
1.1.1.32 root 15604: void msdos_xms_init()
1.1.1.26 root 15605: {
1.1.1.30 root 15606: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
15607: emb_handle_top->address = EMB_TOP;
15608: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 15609: xms_a20_local_enb_count = 0;
15610: }
15611:
1.1.1.32 root 15612: void msdos_xms_finish()
15613: {
15614: msdos_xms_release();
15615: }
15616:
15617: void msdos_xms_release()
1.1.1.30 root 15618: {
15619: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
15620: emb_handle_t *next_handle = emb_handle->next;
15621: free(emb_handle);
15622: emb_handle = next_handle;
15623: }
15624: }
15625:
15626: emb_handle_t *msdos_xms_get_emb_handle(int handle)
15627: {
15628: if(handle != 0) {
15629: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15630: if(emb_handle->handle == handle) {
15631: return(emb_handle);
15632: }
15633: }
15634: }
15635: return(NULL);
15636: }
15637:
15638: int msdos_xms_get_unused_emb_handle_id()
15639: {
15640: for(int handle = 1;; handle++) {
15641: if(msdos_xms_get_emb_handle(handle) == NULL) {
15642: return(handle);
15643: }
15644: }
15645: return(0);
15646: }
15647:
15648: int msdos_xms_get_unused_emb_handle_count()
15649: {
15650: int count = 64; //255;
15651:
15652: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15653: if(emb_handle->handle != 0) {
15654: if(--count == 1) {
15655: break;
15656: }
15657: }
15658: }
15659: return(count);
15660: }
15661:
15662: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
15663: {
15664: if(emb_handle->size_kb > size_kb) {
15665: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
15666:
15667: new_handle->address = emb_handle->address + size_kb * 1024;
15668: new_handle->size_kb = emb_handle->size_kb - size_kb;
15669: emb_handle->size_kb = size_kb;
15670:
15671: new_handle->prev = emb_handle;
15672: new_handle->next = emb_handle->next;
15673: if(emb_handle->next != NULL) {
15674: emb_handle->next->prev = new_handle;
15675: }
15676: emb_handle->next = new_handle;
15677: }
15678: }
15679:
15680: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
15681: {
15682: emb_handle_t *next_handle = emb_handle->next;
15683:
15684: if(next_handle != NULL) {
15685: emb_handle->size_kb += next_handle->size_kb;
15686:
15687: if(next_handle->next != NULL) {
15688: next_handle->next->prev = emb_handle;
15689: }
15690: emb_handle->next = next_handle->next;
15691: free(next_handle);
15692: }
15693: }
15694:
15695: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
15696: {
15697: emb_handle_t *target_handle = NULL;
15698:
15699: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15700: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
15701: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
15702: target_handle = emb_handle;
15703: }
15704: }
15705: }
15706: if(target_handle != NULL) {
15707: if(target_handle->size_kb > size_kb) {
15708: msdos_xms_split_emb_handle(target_handle, size_kb);
15709: }
15710: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
15711: return(target_handle);
15712: }
15713: return(NULL);
15714: }
15715:
15716: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
15717: {
15718: emb_handle_t *prev_handle = emb_handle->prev;
15719: emb_handle_t *next_handle = emb_handle->next;
15720:
15721: if(prev_handle != NULL && prev_handle->handle == 0) {
15722: msdos_xms_combine_emb_handles(prev_handle);
15723: emb_handle = prev_handle;
15724: }
15725: if(next_handle != NULL && next_handle->handle == 0) {
15726: msdos_xms_combine_emb_handles(emb_handle);
15727: }
15728: emb_handle->handle = 0;
15729: }
15730:
1.1.1.19 root 15731: inline void msdos_call_xms_00h()
15732: {
1.1.1.29 root 15733: #if defined(HAS_I386)
15734: REG16(AX) = 0x0300; // V3.00 (XMS Version)
1.1.1.45 root 15735: // REG16(BX) = 0x0395; // V3.95 (Driver Revision in BCD)
1.1.1.29 root 15736: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
15737: #else
15738: REG16(AX) = 0x0200; // V2.00 (XMS Version)
15739: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
15740: #endif
15741: // REG16(DX) = 0x0000; // HMA does not exist
15742: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 15743: }
15744:
15745: inline void msdos_call_xms_01h()
15746: {
1.1.1.29 root 15747: if(REG8(AL) == 0x40) {
15748: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
15749: // DX=KB free extended memory returned by last call of function 08h
15750: REG16(AX) = 0x0000;
15751: REG8(BL) = 0x91;
15752: REG16(DX) = xms_dx_after_call_08h;
15753: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
15754: REG16(AX) = 0x0000;
15755: REG8(BL) = 0x81; // Vdisk was detected
15756: #ifdef SUPPORT_HMA
15757: } else if(is_hma_used_by_int_2fh) {
15758: REG16(AX) = 0x0000;
15759: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
15760: } else if(is_hma_used_by_xms) {
15761: REG16(AX) = 0x0000;
15762: REG8(BL) = 0x91; // HMA is already in use
15763: } else {
15764: REG16(AX) = 0x0001;
15765: is_hma_used_by_xms = true;
15766: #else
15767: } else {
15768: REG16(AX) = 0x0000;
15769: REG8(BL) = 0x91; // HMA is already in use
15770: #endif
15771: }
1.1.1.19 root 15772: }
15773:
15774: inline void msdos_call_xms_02h()
15775: {
1.1.1.29 root 15776: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
15777: REG16(AX) = 0x0000;
15778: REG8(BL) = 0x81; // Vdisk was detected
15779: #ifdef SUPPORT_HMA
15780: } else if(is_hma_used_by_int_2fh) {
15781: REG16(AX) = 0x0000;
15782: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
15783: } else if(!is_hma_used_by_xms) {
15784: REG16(AX) = 0x0000;
15785: REG8(BL) = 0x93; // HMA is not allocated
15786: } else {
15787: REG16(AX) = 0x0001;
15788: is_hma_used_by_xms = false;
15789: // restore first free mcb in high memory area
15790: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
15791: #else
15792: } else {
15793: REG16(AX) = 0x0000;
15794: REG8(BL) = 0x91; // HMA is already in use
15795: #endif
15796: }
1.1.1.19 root 15797: }
15798:
15799: inline void msdos_call_xms_03h()
15800: {
15801: i386_set_a20_line(1);
15802: REG16(AX) = 0x0001;
15803: REG8(BL) = 0x00;
15804: }
15805:
15806: inline void msdos_call_xms_04h()
15807: {
1.1.1.21 root 15808: i386_set_a20_line(0);
15809: REG16(AX) = 0x0001;
15810: REG8(BL) = 0x00;
1.1.1.19 root 15811: }
15812:
15813: inline void msdos_call_xms_05h()
15814: {
15815: i386_set_a20_line(1);
15816: REG16(AX) = 0x0001;
15817: REG8(BL) = 0x00;
1.1.1.21 root 15818: xms_a20_local_enb_count++;
1.1.1.19 root 15819: }
15820:
15821: void msdos_call_xms_06h()
15822: {
1.1.1.21 root 15823: if(xms_a20_local_enb_count > 0) {
1.1.1.45 root 15824: if(--xms_a20_local_enb_count == 0) {
15825: i386_set_a20_line(0);
15826: REG16(AX) = 0x0001;
15827: REG8(BL) = 0x00;
15828: } else {
15829: REG16(AX) = 0x0000;
15830: REG8(BL) = 0x94;
15831: }
1.1.1.21 root 15832: } else {
1.1.1.45 root 15833: i386_set_a20_line(0);
1.1.1.21 root 15834: REG16(AX) = 0x0001;
15835: REG8(BL) = 0x00;
1.1.1.19 root 15836: }
15837: }
15838:
15839: inline void msdos_call_xms_07h()
15840: {
15841: REG16(AX) = (m_a20_mask >> 20) & 1;
15842: REG8(BL) = 0x00;
15843: }
15844:
15845: inline void msdos_call_xms_08h()
15846: {
1.1.1.45 root 15847: UINT32 eax = 0, edx = 0;
1.1.1.19 root 15848:
1.1.1.30 root 15849: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15850: if(emb_handle->handle == 0) {
1.1.1.45 root 15851: if(eax < emb_handle->size_kb) {
15852: eax = emb_handle->size_kb;
1.1.1.19 root 15853: }
1.1.1.45 root 15854: edx += emb_handle->size_kb;
1.1.1.19 root 15855: }
15856: }
1.1.1.45 root 15857: if(eax > 65535) {
15858: eax = 65535;
15859: }
15860: if(edx > 65535) {
15861: edx = 65535;
15862: }
15863: if(eax == 0 && edx == 0) {
1.1.1.19 root 15864: REG8(BL) = 0xa0;
15865: } else {
15866: REG8(BL) = 0x00;
15867: }
1.1.1.45 root 15868: #if defined(HAS_I386)
15869: REG32(EAX) = eax;
15870: REG32(EDX) = edx;
15871: #else
15872: REG16(AX) = (UINT16)eax;
15873: REG16(DX) = (UINT16)edx;
15874: #endif
1.1.1.29 root 15875: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 15876: }
15877:
1.1.1.30 root 15878: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 15879: {
1.1.1.30 root 15880: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
15881:
15882: if(emb_handle != NULL) {
15883: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
15884:
15885: REG16(AX) = 0x0001;
15886: REG16(DX) = emb_handle->handle;
15887: REG8(BL) = 0x00;
15888: } else {
15889: REG16(AX) = REG16(DX) = 0x0000;
15890: REG8(BL) = 0xa0;
1.1.1.19 root 15891: }
1.1.1.30 root 15892: }
15893:
15894: inline void msdos_call_xms_09h()
15895: {
15896: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 15897: }
15898:
15899: inline void msdos_call_xms_0ah()
15900: {
1.1.1.30 root 15901: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15902:
15903: if(emb_handle == NULL) {
1.1.1.19 root 15904: REG16(AX) = 0x0000;
15905: REG8(BL) = 0xa2;
1.1.1.45 root 15906: // } else if(emb_handle->lock > 0) {
15907: // REG16(AX) = 0x0000;
15908: // REG8(BL) = 0xab;
1.1.1.19 root 15909: } else {
1.1.1.30 root 15910: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 15911:
15912: REG16(AX) = 0x0001;
15913: REG8(BL) = 0x00;
15914: }
15915: }
15916:
15917: inline void msdos_call_xms_0bh()
15918: {
15919: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
15920: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
15921: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
15922: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
15923: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
15924:
15925: UINT8 *src_buffer, *dest_buffer;
15926: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 15927: emb_handle_t *emb_handle;
1.1.1.19 root 15928:
15929: if(src_handle == 0) {
15930: src_buffer = mem;
15931: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
15932: src_addr_max = MAX_MEM;
15933: } else {
1.1.1.30 root 15934: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 15935: REG16(AX) = 0x0000;
15936: REG8(BL) = 0xa3;
15937: return;
15938: }
1.1.1.30 root 15939: src_buffer = mem + emb_handle->address;
15940: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 15941: }
15942: if(dest_handle == 0) {
15943: dest_buffer = mem;
15944: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
15945: dest_addr_max = MAX_MEM;
15946: } else {
1.1.1.30 root 15947: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 15948: REG16(AX) = 0x0000;
15949: REG8(BL) = 0xa5;
15950: return;
15951: }
1.1.1.30 root 15952: dest_buffer = mem + emb_handle->address;
15953: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 15954: }
15955: for(int i = 0; i < copy_length; i++) {
15956: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
15957: dest_buffer[dest_addr++] = src_buffer[src_addr++];
15958: } else {
15959: break;
15960: }
15961: }
15962: REG16(AX) = 0x0001;
15963: REG8(BL) = 0x00;
15964: }
15965:
15966: inline void msdos_call_xms_0ch()
15967: {
1.1.1.30 root 15968: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15969:
15970: if(emb_handle == NULL) {
1.1.1.19 root 15971: REG16(AX) = 0x0000;
15972: REG8(BL) = 0xa2;
15973: } else {
1.1.1.45 root 15974: if(emb_handle->lock < 255) {
15975: emb_handle->lock++;
15976: }
1.1.1.19 root 15977: REG16(AX) = 0x0001;
1.1.1.30 root 15978: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
15979: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 15980: }
15981: }
15982:
15983: inline void msdos_call_xms_0dh()
15984: {
1.1.1.30 root 15985: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15986:
15987: if(emb_handle == NULL) {
1.1.1.19 root 15988: REG16(AX) = 0x0000;
15989: REG8(BL) = 0xa2;
1.1.1.30 root 15990: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 15991: REG16(AX) = 0x0000;
15992: REG8(BL) = 0xaa;
15993: } else {
1.1.1.30 root 15994: emb_handle->lock--;
1.1.1.19 root 15995: REG16(AX) = 0x0001;
15996: REG8(BL) = 0x00;
15997: }
15998: }
15999:
16000: inline void msdos_call_xms_0eh()
16001: {
1.1.1.30 root 16002: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16003:
16004: if(emb_handle == NULL) {
1.1.1.19 root 16005: REG16(AX) = 0x0000;
16006: REG8(BL) = 0xa2;
16007: } else {
16008: REG16(AX) = 0x0001;
1.1.1.30 root 16009: REG8(BH) = emb_handle->lock;
16010: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
16011: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 16012: }
16013: }
16014:
1.1.1.30 root 16015: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 16016: {
1.1.1.30 root 16017: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16018:
16019: if(emb_handle == NULL) {
1.1.1.19 root 16020: REG16(AX) = 0x0000;
16021: REG8(BL) = 0xa2;
1.1.1.30 root 16022: } else if(emb_handle->lock > 0) {
1.1.1.19 root 16023: REG16(AX) = 0x0000;
16024: REG8(BL) = 0xab;
16025: } else {
1.1.1.30 root 16026: if(emb_handle->size_kb < size_kb) {
16027: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
16028: msdos_xms_combine_emb_handles(emb_handle);
16029: if(emb_handle->size_kb > size_kb) {
16030: msdos_xms_split_emb_handle(emb_handle, size_kb);
16031: }
16032: } else {
16033: int old_handle = emb_handle->handle;
16034: int old_size_kb = emb_handle->size_kb;
16035: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
16036:
16037: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
16038: msdos_xms_free_emb_handle(emb_handle);
16039:
16040: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
16041: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
16042: }
16043: emb_handle->handle = old_handle;
16044: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
16045: free(buffer);
16046: }
16047: } else if(emb_handle->size_kb > size_kb) {
16048: msdos_xms_split_emb_handle(emb_handle, size_kb);
16049: }
16050: if(emb_handle->size_kb != size_kb) {
16051: REG16(AX) = 0x0000;
16052: REG8(BL) = 0xa0;
16053: } else {
16054: REG16(AX) = 0x0001;
16055: REG8(BL) = 0x00;
16056: }
1.1.1.19 root 16057: }
16058: }
16059:
1.1.1.30 root 16060: inline void msdos_call_xms_0fh()
16061: {
16062: msdos_call_xms_0fh(REG16(BX));
16063: }
16064:
1.1.1.19 root 16065: inline void msdos_call_xms_10h()
16066: {
16067: int seg;
16068:
16069: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
16070: REG16(AX) = 0x0001;
16071: REG16(BX) = seg;
16072: } else {
16073: REG16(AX) = 0x0000;
16074: REG8(BL) = 0xb0;
16075: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
16076: }
16077: }
16078:
16079: inline void msdos_call_xms_11h()
16080: {
16081: int mcb_seg = REG16(DX) - 1;
16082: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
16083:
16084: if(mcb->mz == 'M' || mcb->mz == 'Z') {
16085: msdos_mem_free(REG16(DX));
16086: REG16(AX) = 0x0001;
16087: REG8(BL) = 0x00;
16088: } else {
16089: REG16(AX) = 0x0000;
16090: REG8(BL) = 0xb2;
16091: }
16092: }
16093:
16094: inline void msdos_call_xms_12h()
16095: {
16096: int mcb_seg = REG16(DX) - 1;
16097: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
16098: int max_paragraphs;
16099:
16100: if(mcb->mz == 'M' || mcb->mz == 'Z') {
16101: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
16102: REG16(AX) = 0x0001;
16103: REG8(BL) = 0x00;
16104: } else {
16105: REG16(AX) = 0x0000;
16106: REG8(BL) = 0xb0;
16107: REG16(DX) = max_paragraphs;
16108: }
16109: } else {
16110: REG16(AX) = 0x0000;
16111: REG8(BL) = 0xb2;
16112: }
16113: }
16114:
1.1.1.29 root 16115: #if defined(HAS_I386)
16116:
16117: inline void msdos_call_xms_88h()
16118: {
16119: REG32(EAX) = REG32(EDX) = 0x0000;
16120:
1.1.1.30 root 16121: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
16122: if(emb_handle->handle == 0) {
16123: if(REG32(EAX) < emb_handle->size_kb) {
16124: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 16125: }
1.1.1.30 root 16126: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 16127: }
16128: }
16129: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
16130: REG8(BL) = 0xa0;
16131: } else {
16132: REG8(BL) = 0x00;
16133: }
16134: REG32(ECX) = EMB_END - 1;
16135: }
16136:
16137: inline void msdos_call_xms_89h()
16138: {
1.1.1.30 root 16139: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 16140: }
16141:
16142: inline void msdos_call_xms_8eh()
16143: {
1.1.1.30 root 16144: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
16145:
16146: if(emb_handle == NULL) {
1.1.1.29 root 16147: REG16(AX) = 0x0000;
16148: REG8(BL) = 0xa2;
16149: } else {
16150: REG16(AX) = 0x0001;
1.1.1.30 root 16151: REG8(BH) = emb_handle->lock;
16152: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
16153: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 16154: }
16155: }
16156:
16157: inline void msdos_call_xms_8fh()
16158: {
1.1.1.30 root 16159: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 16160: }
16161:
16162: #endif
1.1.1.19 root 16163: #endif
16164:
1.1.1.26 root 16165: UINT16 msdos_get_equipment()
16166: {
16167: static UINT16 equip = 0;
16168:
16169: if(equip == 0) {
16170: #ifdef SUPPORT_FPU
16171: equip |= (1 << 1); // 80x87 coprocessor installed
16172: #endif
16173: equip |= (1 << 2); // pointing device installed (PS/2)
16174: equip |= (2 << 4); // initial video mode (80x25 color)
16175: // equip |= (1 << 8); // 0 if DMA installed
16176: equip |= (2 << 9); // number of serial ports
16177: equip |= (3 << 14); // number of printer ports (NOTE: this number is 3 on Windows 98 SE though only LPT1 exists)
1.1.1.28 root 16178:
16179: // check only A: and B: if it is floppy drive
16180: int n = 0;
16181: for(int i = 0; i < 2; i++) {
1.1.1.44 root 16182: if(msdos_is_valid_drive(i) && msdos_is_removable_drive(i)) {
16183: n++;
1.1.1.28 root 16184: }
16185: }
16186: if(n != 0) {
16187: equip |= (1 << 0); // floppy disk(s) installed
16188: n--;
16189: equip |= (n << 6); // number of floppies installed less 1
16190: }
16191: // if(joyGetNumDevs() != 0) {
16192: // equip |= (1 << 12); // game port installed
16193: // }
1.1.1.26 root 16194: }
16195: return(equip);
16196: }
16197:
1.1 root 16198: void msdos_syscall(unsigned num)
16199: {
1.1.1.22 root 16200: #ifdef ENABLE_DEBUG_SYSCALL
1.1.1.43 root 16201: if(num == 0x08 || num == 0x1c) {
16202: // don't log the timer interrupts
1.1.1.45 root 16203: // 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));
1.1.1.50 root 16204: } else if(num == 0x30) {
16205: // dummy interrupt for call 0005h (call near)
16206: 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));
1.1.1.43 root 16207: } else if(num == 0x68) {
1.1.1.22 root 16208: // dummy interrupt for EMS (int 67h)
1.1.1.33 root 16209: 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));
1.1.1.22 root 16210: } else if(num == 0x69) {
16211: // dummy interrupt for XMS (call far)
1.1.1.33 root 16212: 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));
1.1.1.50 root 16213: } else if(num >= 0x6a && num <= 0x6f) {
1.1.1.45 root 16214: // dummy interrupt
1.1.1.22 root 16215: } else {
1.1.1.33 root 16216: 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));
1.1.1.22 root 16217: }
16218: #endif
1.1.1.36 root 16219: // update cursor position
16220: if(cursor_moved) {
16221: pcbios_update_cursor_position();
16222: cursor_moved = false;
16223: }
1.1.1.50 root 16224: #ifdef USE_SERVICE_THREAD
16225: // this is called from dummy loop to wait until a serive that waits input is done
16226: if(!in_service)
16227: #endif
1.1.1.33 root 16228: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
1.1.1.22 root 16229:
1.1 root 16230: switch(num) {
16231: case 0x00:
1.1.1.28 root 16232: try {
16233: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16234: error("division by zero\n");
16235: } catch(...) {
16236: fatalerror("division by zero detected, and failed to terminate current process\n");
16237: }
1.1 root 16238: break;
16239: case 0x04:
1.1.1.28 root 16240: try {
16241: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16242: error("overflow\n");
16243: } catch(...) {
16244: fatalerror("overflow detected, and failed to terminate current process\n");
16245: }
1.1 root 16246: break;
16247: case 0x06:
16248: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 16249: if(!ignore_illegal_insn) {
1.1.1.28 root 16250: try {
16251: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16252: error("illegal instruction\n");
16253: } catch(...) {
16254: fatalerror("illegal instruction detected, and failed to terminate current process\n");
16255: }
1.1.1.14 root 16256: } else {
16257: #if defined(HAS_I386)
1.1.1.39 root 16258: m_eip = m_int6h_skip_eip;
16259: #elif defined(HAS_I286)
16260: m_pc = m_int6h_skip_pc;
1.1.1.14 root 16261: #else
1.1.1.39 root 16262: // 8086/80186 ignore an invalid opcode
1.1.1.14 root 16263: #endif
16264: }
1.1 root 16265: break;
1.1.1.33 root 16266: case 0x09:
16267: // ctrl-break is pressed
16268: if(raise_int_1bh) {
16269: #if defined(HAS_I386)
16270: m_ext = 0; // not an external interrupt
16271: i386_trap(0x1b, 1, 0);
16272: m_ext = 1;
16273: #else
16274: PREFIX86(_interrupt)(0x1b);
16275: #endif
16276: raise_int_1bh = false;
16277: }
1.1.1.8 root 16278: case 0x08:
1.1.1.14 root 16279: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 16280: case 0x0b:
16281: case 0x0c:
16282: case 0x0d:
16283: case 0x0e:
16284: case 0x0f:
16285: // EOI
16286: pic[0].isr &= ~(1 << (num - 0x08));
16287: pic_update();
16288: break;
1.1 root 16289: case 0x10:
16290: // PC BIOS - Video
1.1.1.14 root 16291: if(!restore_console_on_exit) {
1.1.1.15 root 16292: change_console_size(scr_width, scr_height);
1.1 root 16293: }
1.1.1.3 root 16294: m_CF = 0;
1.1 root 16295: switch(REG8(AH)) {
1.1.1.16 root 16296: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 16297: case 0x01: pcbios_int_10h_01h(); break;
16298: case 0x02: pcbios_int_10h_02h(); break;
16299: case 0x03: pcbios_int_10h_03h(); break;
16300: case 0x05: pcbios_int_10h_05h(); break;
16301: case 0x06: pcbios_int_10h_06h(); break;
16302: case 0x07: pcbios_int_10h_07h(); break;
16303: case 0x08: pcbios_int_10h_08h(); break;
16304: case 0x09: pcbios_int_10h_09h(); break;
16305: case 0x0a: pcbios_int_10h_0ah(); break;
16306: case 0x0b: break;
1.1.1.40 root 16307: case 0x0c: pcbios_int_10h_0ch(); break;
16308: case 0x0d: pcbios_int_10h_0dh(); break;
1.1 root 16309: case 0x0e: pcbios_int_10h_0eh(); break;
16310: case 0x0f: pcbios_int_10h_0fh(); break;
16311: case 0x10: break;
1.1.1.14 root 16312: case 0x11: pcbios_int_10h_11h(); break;
16313: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 16314: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 16315: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 16316: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 16317: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
16318: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 16319: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 16320: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
16321: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 16322: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 16323: case 0x6f: break;
1.1.1.22 root 16324: case 0x80: m_CF = 1; break; // unknown
16325: case 0x81: m_CF = 1; break; // unknown
1.1 root 16326: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 16327: case 0x83: pcbios_int_10h_83h(); break;
16328: case 0x8b: break;
16329: case 0x8c: m_CF = 1; break; // unknown
16330: case 0x8d: m_CF = 1; break; // unknown
16331: case 0x8e: m_CF = 1; break; // unknown
16332: case 0x90: pcbios_int_10h_90h(); break;
16333: case 0x91: pcbios_int_10h_91h(); break;
16334: case 0x92: break;
16335: case 0x93: break;
16336: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 16337: case 0xfa: break; // ega register interface library is not installed
1.1 root 16338: case 0xfe: pcbios_int_10h_feh(); break;
16339: case 0xff: pcbios_int_10h_ffh(); break;
16340: default:
1.1.1.22 root 16341: 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));
16342: m_CF = 1;
1.1 root 16343: break;
16344: }
16345: break;
16346: case 0x11:
16347: // PC BIOS - Get Equipment List
1.1.1.26 root 16348: REG16(AX) = msdos_get_equipment();
1.1 root 16349: break;
16350: case 0x12:
16351: // PC BIOS - Get Memory Size
1.1.1.33 root 16352: REG16(AX) = *(UINT16 *)(mem + 0x413);
1.1 root 16353: break;
16354: case 0x13:
1.1.1.42 root 16355: // PC BIOS - Disk I/O
16356: {
16357: static UINT8 last = 0x00;
16358: switch(REG8(AH)) {
16359: case 0x00: pcbios_int_13h_00h(); break;
16360: case 0x01: // get last status
16361: REG8(AH) = last;
16362: break;
16363: case 0x02: pcbios_int_13h_02h(); break;
16364: case 0x03: pcbios_int_13h_03h(); break;
16365: case 0x04: pcbios_int_13h_04h(); break;
16366: case 0x08: pcbios_int_13h_08h(); break;
16367: case 0x0a: pcbios_int_13h_02h(); break;
16368: case 0x0b: pcbios_int_13h_03h(); break;
16369: case 0x0d: pcbios_int_13h_00h(); break;
16370: case 0x10: pcbios_int_13h_10h(); break;
16371: case 0x15: pcbios_int_13h_15h(); break;
1.1.1.43 root 16372: case 0x41: pcbios_int_13h_41h(); break;
1.1.1.42 root 16373: case 0x05: // format
16374: case 0x06:
16375: case 0x07:
16376: REG8(AH) = 0x0c; // unsupported track or invalid media
16377: m_CF = 1;
16378: break;
16379: case 0x09:
16380: case 0x0c: // seek
16381: case 0x11: // recalib
16382: case 0x14:
16383: case 0x17:
16384: REG8(AH) = 0x00; // successful completion
16385: break;
1.1.1.43 root 16386: case 0x21: // QUICKCACHE II v4.20 - Flush Cache
16387: case 0xa1: // Super PC-Kwik v3.20+ - Flush Cache
16388: REG8(AH) = 0x01; // invalid function
16389: m_CF = 1;
16390: break;
1.1.1.42 root 16391: default:
16392: 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));
16393: REG8(AH) = 0x01; // invalid function
16394: m_CF = 1;
16395: break;
16396: }
16397: last = REG8(AH);
16398: }
1.1 root 16399: break;
16400: case 0x14:
16401: // PC BIOS - Serial I/O
1.1.1.25 root 16402: switch(REG8(AH)) {
16403: case 0x00: pcbios_int_14h_00h(); break;
16404: case 0x01: pcbios_int_14h_01h(); break;
16405: case 0x02: pcbios_int_14h_02h(); break;
16406: case 0x03: pcbios_int_14h_03h(); break;
16407: case 0x04: pcbios_int_14h_04h(); break;
16408: case 0x05: pcbios_int_14h_05h(); break;
16409: default:
16410: 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));
16411: break;
16412: }
1.1 root 16413: break;
16414: case 0x15:
16415: // PC BIOS
1.1.1.3 root 16416: m_CF = 0;
1.1 root 16417: switch(REG8(AH)) {
1.1.1.14 root 16418: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 16419: case 0x23: pcbios_int_15h_23h(); break;
16420: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 16421: case 0x41: break;
1.1 root 16422: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 16423: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 16424: case 0x53: pcbios_int_15h_53h(); break;
1.1.1.43 root 16425: case 0x84: pcbios_int_15h_84h(); break;
1.1 root 16426: case 0x86: pcbios_int_15h_86h(); break;
16427: case 0x87: pcbios_int_15h_87h(); break;
16428: case 0x88: pcbios_int_15h_88h(); break;
16429: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 16430: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 16431: case 0xc0: // PS/2 ???
16432: case 0xc1:
16433: case 0xc2:
1.1.1.30 root 16434: case 0xc3: // PS50+ ???
16435: case 0xc4:
1.1.1.22 root 16436: REG8(AH) = 0x86;
16437: m_CF = 1;
16438: break;
1.1.1.3 root 16439: #if defined(HAS_I386)
1.1 root 16440: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 16441: #endif
1.1 root 16442: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 16443: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 16444: default:
1.1.1.22 root 16445: 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));
16446: REG8(AH) = 0x86;
1.1.1.3 root 16447: m_CF = 1;
1.1 root 16448: break;
16449: }
16450: break;
16451: case 0x16:
16452: // PC BIOS - Keyboard
1.1.1.3 root 16453: m_CF = 0;
1.1 root 16454: switch(REG8(AH)) {
16455: case 0x00: pcbios_int_16h_00h(); break;
16456: case 0x01: pcbios_int_16h_01h(); break;
16457: case 0x02: pcbios_int_16h_02h(); break;
16458: case 0x03: pcbios_int_16h_03h(); break;
16459: case 0x05: pcbios_int_16h_05h(); break;
16460: case 0x10: pcbios_int_16h_00h(); break;
16461: case 0x11: pcbios_int_16h_01h(); break;
16462: case 0x12: pcbios_int_16h_12h(); break;
16463: case 0x13: pcbios_int_16h_13h(); break;
16464: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 16465: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 16466: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 16467: case 0xda: break; // unknown
1.1.1.43 root 16468: case 0xdb: break; // unknown
1.1.1.22 root 16469: case 0xff: break; // unknown
1.1 root 16470: default:
1.1.1.22 root 16471: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 16472: break;
16473: }
16474: break;
16475: case 0x17:
16476: // PC BIOS - Printer
1.1.1.37 root 16477: m_CF = 0;
16478: switch(REG8(AH)) {
16479: case 0x00: pcbios_int_17h_00h(); break;
16480: case 0x01: pcbios_int_17h_01h(); break;
16481: case 0x02: pcbios_int_17h_02h(); break;
16482: case 0x03: pcbios_int_17h_03h(); break;
16483: case 0x50: pcbios_int_17h_50h(); break;
16484: case 0x51: pcbios_int_17h_51h(); break;
16485: case 0x52: pcbios_int_17h_52h(); break;
16486: case 0x84: pcbios_int_17h_84h(); break;
16487: case 0x85: pcbios_int_17h_85h(); break;
16488: default:
16489: 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));
16490: break;
16491: }
1.1 root 16492: break;
16493: case 0x1a:
16494: // PC BIOS - Timer
1.1.1.3 root 16495: m_CF = 0;
1.1 root 16496: switch(REG8(AH)) {
16497: case 0x00: pcbios_int_1ah_00h(); break;
16498: case 0x01: break;
16499: case 0x02: pcbios_int_1ah_02h(); break;
16500: case 0x03: break;
16501: case 0x04: pcbios_int_1ah_04h(); break;
16502: case 0x05: break;
16503: case 0x0a: pcbios_int_1ah_0ah(); break;
16504: case 0x0b: break;
1.1.1.14 root 16505: case 0x35: break; // Word Perfect Third Party Interface?
16506: case 0x36: break; // Word Perfect Third Party Interface
16507: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1.1.44 root 16508: case 0xb0: break; // Microsoft Real-Time Compression Interface (MRCI)
1.1.1.43 root 16509: case 0xb1: break; // PCI BIOS v2.0c+
16510: case 0xb4: break; // Intel Plug-and-Play Auto-Configuration
1.1 root 16511: default:
1.1.1.22 root 16512: unimplemented_1ah("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 16513: break;
16514: }
16515: break;
1.1.1.33 root 16516: case 0x1b:
16517: mem[0x471] = 0x00;
16518: break;
1.1 root 16519: case 0x20:
1.1.1.28 root 16520: try {
16521: msdos_process_terminate(SREG(CS), retval, 1);
16522: } catch(...) {
16523: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
16524: }
1.1 root 16525: break;
1.1.1.49 root 16526: case 0x30:
1.1.1.46 root 16527: // dummy interrupt for case map routine pointed in the country info
16528: // if(!(REG8(CL) >= 0x00 && REG8(CL) <= 0x24)) {
16529: // REG8(AL) = 0x00;
16530: // break;
16531: // }
1.1 root 16532: case 0x21:
16533: // MS-DOS System Call
1.1.1.3 root 16534: m_CF = 0;
1.1.1.28 root 16535: try {
1.1.1.46 root 16536: switch(num == 0x21 ? REG8(AH) : REG8(CL)) {
1.1.1.28 root 16537: case 0x00: msdos_int_21h_00h(); break;
16538: case 0x01: msdos_int_21h_01h(); break;
16539: case 0x02: msdos_int_21h_02h(); break;
16540: case 0x03: msdos_int_21h_03h(); break;
16541: case 0x04: msdos_int_21h_04h(); break;
16542: case 0x05: msdos_int_21h_05h(); break;
16543: case 0x06: msdos_int_21h_06h(); break;
16544: case 0x07: msdos_int_21h_07h(); break;
16545: case 0x08: msdos_int_21h_08h(); break;
16546: case 0x09: msdos_int_21h_09h(); break;
16547: case 0x0a: msdos_int_21h_0ah(); break;
16548: case 0x0b: msdos_int_21h_0bh(); break;
16549: case 0x0c: msdos_int_21h_0ch(); break;
16550: case 0x0d: msdos_int_21h_0dh(); break;
16551: case 0x0e: msdos_int_21h_0eh(); break;
16552: case 0x0f: msdos_int_21h_0fh(); break;
16553: case 0x10: msdos_int_21h_10h(); break;
16554: case 0x11: msdos_int_21h_11h(); break;
16555: case 0x12: msdos_int_21h_12h(); break;
16556: case 0x13: msdos_int_21h_13h(); break;
16557: case 0x14: msdos_int_21h_14h(); break;
16558: case 0x15: msdos_int_21h_15h(); break;
16559: case 0x16: msdos_int_21h_16h(); break;
16560: case 0x17: msdos_int_21h_17h(); break;
16561: case 0x18: msdos_int_21h_18h(); break;
16562: case 0x19: msdos_int_21h_19h(); break;
16563: case 0x1a: msdos_int_21h_1ah(); break;
16564: case 0x1b: msdos_int_21h_1bh(); break;
16565: case 0x1c: msdos_int_21h_1ch(); break;
16566: case 0x1d: msdos_int_21h_1dh(); break;
16567: case 0x1e: msdos_int_21h_1eh(); break;
16568: case 0x1f: msdos_int_21h_1fh(); break;
16569: case 0x20: msdos_int_21h_20h(); break;
16570: case 0x21: msdos_int_21h_21h(); break;
16571: case 0x22: msdos_int_21h_22h(); break;
16572: case 0x23: msdos_int_21h_23h(); break;
16573: case 0x24: msdos_int_21h_24h(); break;
16574: case 0x25: msdos_int_21h_25h(); break;
16575: case 0x26: msdos_int_21h_26h(); break;
16576: case 0x27: msdos_int_21h_27h(); break;
16577: case 0x28: msdos_int_21h_28h(); break;
16578: case 0x29: msdos_int_21h_29h(); break;
16579: case 0x2a: msdos_int_21h_2ah(); break;
16580: case 0x2b: msdos_int_21h_2bh(); break;
16581: case 0x2c: msdos_int_21h_2ch(); break;
16582: case 0x2d: msdos_int_21h_2dh(); break;
16583: case 0x2e: msdos_int_21h_2eh(); break;
16584: case 0x2f: msdos_int_21h_2fh(); break;
16585: case 0x30: msdos_int_21h_30h(); break;
16586: case 0x31: msdos_int_21h_31h(); break;
16587: case 0x32: msdos_int_21h_32h(); break;
16588: case 0x33: msdos_int_21h_33h(); break;
16589: case 0x34: msdos_int_21h_34h(); break;
16590: case 0x35: msdos_int_21h_35h(); break;
16591: case 0x36: msdos_int_21h_36h(); break;
16592: case 0x37: msdos_int_21h_37h(); break;
16593: case 0x38: msdos_int_21h_38h(); break;
16594: case 0x39: msdos_int_21h_39h(0); break;
16595: case 0x3a: msdos_int_21h_3ah(0); break;
16596: case 0x3b: msdos_int_21h_3bh(0); break;
16597: case 0x3c: msdos_int_21h_3ch(); break;
16598: case 0x3d: msdos_int_21h_3dh(); break;
16599: case 0x3e: msdos_int_21h_3eh(); break;
16600: case 0x3f: msdos_int_21h_3fh(); break;
16601: case 0x40: msdos_int_21h_40h(); break;
16602: case 0x41: msdos_int_21h_41h(0); break;
16603: case 0x42: msdos_int_21h_42h(); break;
16604: case 0x43: msdos_int_21h_43h(0); break;
16605: case 0x44: msdos_int_21h_44h(); break;
16606: case 0x45: msdos_int_21h_45h(); break;
16607: case 0x46: msdos_int_21h_46h(); break;
16608: case 0x47: msdos_int_21h_47h(0); break;
16609: case 0x48: msdos_int_21h_48h(); break;
16610: case 0x49: msdos_int_21h_49h(); break;
16611: case 0x4a: msdos_int_21h_4ah(); break;
16612: case 0x4b: msdos_int_21h_4bh(); break;
16613: case 0x4c: msdos_int_21h_4ch(); break;
16614: case 0x4d: msdos_int_21h_4dh(); break;
16615: case 0x4e: msdos_int_21h_4eh(); break;
16616: case 0x4f: msdos_int_21h_4fh(); break;
16617: case 0x50: msdos_int_21h_50h(); break;
16618: case 0x51: msdos_int_21h_51h(); break;
16619: case 0x52: msdos_int_21h_52h(); break;
1.1.1.43 root 16620: case 0x53: msdos_int_21h_53h(); break;
1.1.1.28 root 16621: case 0x54: msdos_int_21h_54h(); break;
16622: case 0x55: msdos_int_21h_55h(); break;
16623: case 0x56: msdos_int_21h_56h(0); break;
16624: case 0x57: msdos_int_21h_57h(); break;
16625: case 0x58: msdos_int_21h_58h(); break;
16626: case 0x59: msdos_int_21h_59h(); break;
16627: case 0x5a: msdos_int_21h_5ah(); break;
16628: case 0x5b: msdos_int_21h_5bh(); break;
16629: case 0x5c: msdos_int_21h_5ch(); break;
16630: case 0x5d: msdos_int_21h_5dh(); break;
1.1.1.42 root 16631: case 0x5e: msdos_int_21h_5eh(); break;
1.1.1.30 root 16632: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 16633: case 0x60: msdos_int_21h_60h(0); break;
16634: case 0x61: msdos_int_21h_61h(); break;
16635: case 0x62: msdos_int_21h_62h(); break;
16636: case 0x63: msdos_int_21h_63h(); break;
1.1.1.33 root 16637: // 0x64: Set Device Driver Lockahead Flag
1.1.1.28 root 16638: case 0x65: msdos_int_21h_65h(); break;
16639: case 0x66: msdos_int_21h_66h(); break;
16640: case 0x67: msdos_int_21h_67h(); break;
16641: case 0x68: msdos_int_21h_68h(); break;
16642: case 0x69: msdos_int_21h_69h(); break;
16643: case 0x6a: msdos_int_21h_6ah(); break;
16644: case 0x6b: msdos_int_21h_6bh(); break;
16645: case 0x6c: msdos_int_21h_6ch(0); break;
1.1.1.48 root 16646: case 0x6d: // Find First ROM Program
16647: case 0x6e: // Find Next ROM Program
16648: case 0x6f: // Get/Set ROM Scan Start Address
16649: REG8(AL) = 0x00; // if not supported (DOS <5, MS-DOS 5+ non-ROM versions)
16650: break;
1.1.1.43 root 16651: case 0x70: msdos_int_21h_70h(); break;
1.1.1.48 root 16652: case 0x71: // Windows95 - Long Filename Functions
1.1.1.28 root 16653: switch(REG8(AL)) {
16654: case 0x0d: msdos_int_21h_710dh(); break;
16655: case 0x39: msdos_int_21h_39h(1); break;
16656: case 0x3a: msdos_int_21h_3ah(1); break;
16657: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.48 root 16658: case 0x41: msdos_int_21h_7141h(); break;
1.1.1.28 root 16659: case 0x43: msdos_int_21h_43h(1); break;
16660: case 0x47: msdos_int_21h_47h(1); break;
16661: case 0x4e: msdos_int_21h_714eh(); break;
16662: case 0x4f: msdos_int_21h_714fh(); break;
16663: case 0x56: msdos_int_21h_56h(1); break;
16664: case 0x60: msdos_int_21h_60h(1); break;
16665: case 0x6c: msdos_int_21h_6ch(1); break;
16666: case 0xa0: msdos_int_21h_71a0h(); break;
16667: case 0xa1: msdos_int_21h_71a1h(); break;
16668: case 0xa6: msdos_int_21h_71a6h(); break;
16669: case 0xa7: msdos_int_21h_71a7h(); break;
16670: case 0xa8: msdos_int_21h_71a8h(); break;
1.1.1.45 root 16671: case 0xa9: msdos_int_21h_6ch(1); break;
1.1.1.28 root 16672: case 0xaa: msdos_int_21h_71aah(); break;
16673: default:
16674: 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));
16675: REG16(AX) = 0x7100;
16676: m_CF = 1;
16677: break;
16678: }
16679: break;
1.1.1.48 root 16680: case 0x72: // Windows95 beta - LFN FindClose
16681: // 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));
16682: REG16(AX) = 0x7200;
16683: m_CF = 1;
16684: break;
16685: case 0x73: // Windows95 - FAT32 Functions
1.1.1.28 root 16686: switch(REG8(AL)) {
16687: case 0x00: msdos_int_21h_7300h(); break;
1.1.1.33 root 16688: // 0x01: Set Drive Locking ???
1.1.1.28 root 16689: case 0x02: msdos_int_21h_7302h(); break;
16690: case 0x03: msdos_int_21h_7303h(); break;
1.1.1.33 root 16691: // 0x04: Set DPB to Use for Formatting
16692: // 0x05: Extended Absolute Disk Read/Write
1.1.1.28 root 16693: default:
16694: 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));
16695: REG16(AX) = 0x7300;
16696: m_CF = 1;
16697: break;
16698: }
1.1 root 16699: break;
1.1.1.30 root 16700: case 0xdb: msdos_int_21h_dbh(); break;
16701: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 16702: default:
1.1.1.22 root 16703: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.28 root 16704: REG16(AX) = 0x01;
1.1.1.3 root 16705: m_CF = 1;
1.1 root 16706: break;
16707: }
1.1.1.28 root 16708: } catch(int error) {
16709: REG16(AX) = error;
16710: m_CF = 1;
16711: } catch(...) {
16712: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 16713: m_CF = 1;
1.1 root 16714: }
1.1.1.3 root 16715: if(m_CF) {
1.1.1.23 root 16716: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1.1.1.47 root 16717: sda->int21h_5d0ah_called = 0;
1.1.1.23 root 16718: sda->extended_error_code = REG16(AX);
16719: switch(sda->extended_error_code) {
16720: case 4: // Too many open files
16721: case 8: // Insufficient memory
16722: sda->error_class = 1; // Out of resource
16723: break;
16724: case 5: // Access denied
16725: sda->error_class = 3; // Authorization
16726: break;
16727: case 7: // Memory control block destroyed
16728: sda->error_class = 4; // Internal
16729: break;
16730: case 2: // File not found
16731: case 3: // Path not found
16732: case 15: // Invaid drive specified
16733: case 18: // No more files
16734: sda->error_class = 8; // Not found
16735: break;
16736: case 32: // Sharing violation
16737: case 33: // Lock violation
16738: sda->error_class = 10; // Locked
16739: break;
16740: // case 16: // Removal of current directory attempted
16741: case 19: // Attempted write on protected disk
16742: case 21: // Drive not ready
16743: // case 29: // Write failure
16744: // case 30: // Read failure
16745: // case 82: // Cannot create subdirectory
16746: sda->error_class = 11; // Media
16747: break;
16748: case 80: // File already exists
16749: sda->error_class = 12; // Already exist
16750: break;
16751: default:
16752: sda->error_class = 13; // Unknown
16753: break;
16754: }
16755: sda->suggested_action = 1; // Retry
16756: sda->locus_of_last_error = 1; // Unknown
1.1 root 16757: }
1.1.1.33 root 16758: if(ctrl_break_checking && ctrl_break_detected) {
1.1.1.26 root 16759: // raise int 23h
16760: #if defined(HAS_I386)
16761: m_ext = 0; // not an external interrupt
16762: i386_trap(0x23, 1, 0);
16763: m_ext = 1;
16764: #else
16765: PREFIX86(_interrupt)(0x23);
16766: #endif
16767: }
1.1 root 16768: break;
16769: case 0x22:
16770: fatalerror("int 22h (terminate address)\n");
16771: case 0x23:
1.1.1.28 root 16772: try {
16773: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
16774: } catch(...) {
16775: fatalerror("failed to terminate the current process by int 23h\n");
16776: }
1.1 root 16777: break;
16778: case 0x24:
1.1.1.32 root 16779: /*
1.1.1.28 root 16780: try {
16781: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16782: } catch(...) {
16783: fatalerror("failed to terminate the current process by int 24h\n");
16784: }
1.1.1.32 root 16785: */
16786: msdos_int_24h();
1.1 root 16787: break;
16788: case 0x25:
16789: msdos_int_25h();
16790: break;
16791: case 0x26:
16792: msdos_int_26h();
16793: break;
16794: case 0x27:
1.1.1.28 root 16795: try {
16796: msdos_int_27h();
16797: } catch(...) {
16798: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
16799: }
1.1 root 16800: break;
16801: case 0x28:
16802: Sleep(10);
1.1.1.35 root 16803: REQUEST_HARDWRE_UPDATE();
1.1 root 16804: break;
16805: case 0x29:
16806: msdos_int_29h();
16807: break;
16808: case 0x2e:
16809: msdos_int_2eh();
16810: break;
16811: case 0x2f:
16812: // multiplex interrupt
16813: switch(REG8(AH)) {
1.1.1.22 root 16814: case 0x05: msdos_int_2fh_05h(); break;
1.1.1.44 root 16815: case 0x06: msdos_int_2fh_06h(); break;
1.1.1.22 root 16816: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 16817: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 16818: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 16819: case 0x14: msdos_int_2fh_14h(); break;
16820: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 16821: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 16822: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 16823: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 16824: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 16825: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 16826: case 0x46: msdos_int_2fh_46h(); break;
16827: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 16828: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 16829: case 0x4b: msdos_int_2fh_4bh(); break;
1.1.1.44 root 16830: case 0x4d: msdos_int_2fh_4dh(); break;
1.1 root 16831: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 16832: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.44 root 16833: case 0x56: msdos_int_2fh_56h(); break;
1.1.1.24 root 16834: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 16835: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.34 root 16836: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.43 root 16837: default:
1.1.1.30 root 16838: switch(REG8(AL)) {
16839: case 0x00:
16840: // This is not installed
16841: // REG8(AL) = 0x00;
16842: break;
1.1.1.33 root 16843: case 0x01:
1.1.1.42 root 16844: // Quarterdeck RPCI - QEMM/QRAM - PCL-838.EXE is not installed
16845: if(REG8(AH) == 0xd2 && REG16(BX) == 0x5145 && REG16(CX) == 0x4d4d && REG16(DX) == 0x3432) {
16846: break;
16847: }
1.1.1.33 root 16848: // Banyan VINES v4+ is not installed
16849: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
16850: break;
16851: }
1.1.1.42 root 16852: // Quarterdeck QDPMI.SYS v1.0 is not installed
16853: if(REG8(AH) == 0xde && REG16(BX) == 0x4450 && REG16(CX) == 0x4d49 && REG16(DX) == 0x8f4f) {
16854: break;
16855: }
1.1.1.30 root 16856: default:
1.1.1.42 root 16857: // NORTON UTILITIES 5.0+
16858: if(REG8(AH) == 0xfe && REG16(DI) == 0x4e55) {
16859: break;
16860: }
1.1.1.30 root 16861: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.43 root 16862: REG16(AX) = 0x01; // invalid function
1.1.1.30 root 16863: m_CF = 1;
16864: break;
16865: }
16866: break;
1.1 root 16867: }
16868: break;
1.1.1.24 root 16869: case 0x33:
16870: switch(REG8(AH)) {
16871: case 0x00:
16872: // Mouse
1.1.1.49 root 16873: switch(REG16(AX)) {
16874: case 0x0000: msdos_int_33h_0000h(); break;
16875: case 0x0001: msdos_int_33h_0001h(); break;
16876: case 0x0002: msdos_int_33h_0002h(); break;
16877: case 0x0003: msdos_int_33h_0003h(); break;
16878: case 0x0004: msdos_int_33h_0004h(); break;
16879: case 0x0005: msdos_int_33h_0005h(); break;
16880: case 0x0006: msdos_int_33h_0006h(); break;
16881: case 0x0007: msdos_int_33h_0007h(); break;
16882: case 0x0008: msdos_int_33h_0008h(); break;
16883: case 0x0009: msdos_int_33h_0009h(); break;
16884: case 0x000a: msdos_int_33h_000ah(); break;
16885: case 0x000b: msdos_int_33h_000bh(); break;
16886: case 0x000c: msdos_int_33h_000ch(); break;
16887: case 0x000d: break; // MS MOUSE v1.0+ - Light Pen Emulation On
16888: case 0x000e: break; // MS MOUSE v1.0+ - Light Pen Emulation Off
16889: case 0x000f: msdos_int_33h_000fh(); break;
16890: case 0x0010: break; // MS MOUSE v1.0+ - Define Screen Region for Updating
16891: case 0x0011: msdos_int_33h_0011h(); break;
16892: case 0x0012: REG16(AX) = 0xffff; break; // MS MOUSE - Set Large Graphics Cursor Block
16893: case 0x0013: break; // MS MOUSE v5.0+ - Define Double-Speed Threshold
16894: case 0x0014: msdos_int_33h_0014h(); break;
16895: case 0x0015: msdos_int_33h_0015h(); break;
16896: case 0x0016: msdos_int_33h_0016h(); break;
16897: case 0x0017: msdos_int_33h_0017h(); break;
16898: case 0x0018: msdos_int_33h_0018h(); break;
16899: case 0x0019: msdos_int_33h_0019h(); break;
16900: case 0x001a: msdos_int_33h_001ah(); break;
16901: case 0x001b: msdos_int_33h_001bh(); break;
16902: case 0x001c: break; // MS MOUSE v6.0+ - Set Interrupt Rate
16903: case 0x001d: msdos_int_33h_001dh(); break;
16904: case 0x001e: msdos_int_33h_001eh(); break;
16905: case 0x001f: msdos_int_33h_001fh(); break;
16906: case 0x0020: msdos_int_33h_0020h(); break;
16907: case 0x0021: msdos_int_33h_0021h(); break;
16908: case 0x0022: msdos_int_33h_0022h(); break;
16909: case 0x0023: msdos_int_33h_0023h(); break;
16910: case 0x0024: msdos_int_33h_0024h(); break;
16911: case 0x0025: msdos_int_33h_0025h(); break;
16912: case 0x0026: msdos_int_33h_0026h(); break;
16913: case 0x0027: msdos_int_33h_0027h(); break;
16914: case 0x0028: msdos_int_33h_0028h(); break;
16915: case 0x0029: msdos_int_33h_0029h(); break;
16916: case 0x002a: msdos_int_33h_002ah(); break;
16917: // 0x002b: MS MOUSE v7.0+ - Load Acceleration Profiles
16918: // 0x002c: MS MOUSE v7.0+ - Get Acceleration Profiles
16919: // 0x002d: MS MOUSE v7.0+ - Select Acceleration Profile
16920: // 0x002e: MS MOUSE v8.10+ - Set Acceleration Profile Names
16921: case 0x002f: break; // Mouse Hardware Reset
16922: // 0x0030: MS MOUSE v7.04+ - Get/Set BallPoint Information
16923: case 0x0031: msdos_int_33h_0031h(); break;
16924: case 0x0032: msdos_int_33h_0032h(); break;
16925: // 0x0033: MS MOUSE v7.05+ - Get Switch Settings And Acceleration Profile Data
16926: // 0x0034: MS MOUSE v8.0+ - Get Initialization File
16927: // 0x0035: MS MOUSE v8.10+ - LCD Screen Large Pointer Support
16928: case 0x004d: msdos_int_33h_004dh(); break;
16929: case 0x006d: msdos_int_33h_006dh(); break;
1.1.1.24 root 16930: default:
16931: 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));
16932: break;
16933: }
16934: break;
16935: default:
16936: 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));
16937: break;
16938: }
16939: break;
1.1.1.50 root 16940: /*
16941: case 0x67:
16942: // int 67h handler is in EMS device driver (EMMXXXX0) and it calls int 68h
16943: // NOTE: some softwares get address of int 67h handler and recognize the address is in EMS device driver
16944: break;
16945: */
1.1.1.19 root 16946: case 0x68:
16947: // dummy interrupt for EMS (int 67h)
16948: switch(REG8(AH)) {
16949: case 0x40: msdos_int_67h_40h(); break;
16950: case 0x41: msdos_int_67h_41h(); break;
16951: case 0x42: msdos_int_67h_42h(); break;
16952: case 0x43: msdos_int_67h_43h(); break;
16953: case 0x44: msdos_int_67h_44h(); break;
16954: case 0x45: msdos_int_67h_45h(); break;
16955: case 0x46: msdos_int_67h_46h(); break;
16956: case 0x47: msdos_int_67h_47h(); break;
16957: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 16958: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
16959: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 16960: case 0x4b: msdos_int_67h_4bh(); break;
16961: case 0x4c: msdos_int_67h_4ch(); break;
16962: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 16963: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 16964: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 16965: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 16966: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 16967: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 16968: case 0x53: msdos_int_67h_53h(); break;
16969: case 0x54: msdos_int_67h_54h(); break;
1.1.1.49 root 16970: case 0x55: msdos_int_67h_55h(); break;
16971: case 0x56: msdos_int_67h_56h(); break;
1.1.1.20 root 16972: case 0x57: msdos_int_67h_57h(); break;
16973: case 0x58: msdos_int_67h_58h(); break;
1.1.1.42 root 16974: case 0x59: msdos_int_67h_59h(); break;
1.1.1.20 root 16975: case 0x5a: msdos_int_67h_5ah(); break;
1.1.1.49 root 16976: case 0x5b: msdos_int_67h_5bh(); break;
1.1.1.43 root 16977: // 0x5c: LIM EMS 4.0 - Prepare Expanded Memory Hardware For Warm Boot
16978: case 0x5d: msdos_int_67h_5dh(); break;
1.1.1.49 root 16979: case 0x70: msdos_int_67h_70h(); break;
1.1.1.31 root 16980: // 0xde: VCPI
1.1.1.30 root 16981: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 16982: default:
1.1.1.22 root 16983: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.19 root 16984: REG8(AH) = 0x84;
16985: break;
16986: }
16987: break;
16988: #ifdef SUPPORT_XMS
16989: case 0x69:
16990: // dummy interrupt for XMS (call far)
1.1.1.28 root 16991: try {
16992: switch(REG8(AH)) {
16993: case 0x00: msdos_call_xms_00h(); break;
16994: case 0x01: msdos_call_xms_01h(); break;
16995: case 0x02: msdos_call_xms_02h(); break;
16996: case 0x03: msdos_call_xms_03h(); break;
16997: case 0x04: msdos_call_xms_04h(); break;
16998: case 0x05: msdos_call_xms_05h(); break;
16999: case 0x06: msdos_call_xms_06h(); break;
17000: case 0x07: msdos_call_xms_07h(); break;
17001: case 0x08: msdos_call_xms_08h(); break;
17002: case 0x09: msdos_call_xms_09h(); break;
17003: case 0x0a: msdos_call_xms_0ah(); break;
17004: case 0x0b: msdos_call_xms_0bh(); break;
17005: case 0x0c: msdos_call_xms_0ch(); break;
17006: case 0x0d: msdos_call_xms_0dh(); break;
17007: case 0x0e: msdos_call_xms_0eh(); break;
17008: case 0x0f: msdos_call_xms_0fh(); break;
17009: case 0x10: msdos_call_xms_10h(); break;
17010: case 0x11: msdos_call_xms_11h(); break;
17011: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 17012: #if defined(HAS_I386)
17013: case 0x88: msdos_call_xms_88h(); break;
17014: case 0x89: msdos_call_xms_89h(); break;
17015: case 0x8e: msdos_call_xms_8eh(); break;
17016: case 0x8f: msdos_call_xms_8fh(); break;
17017: #endif
1.1.1.28 root 17018: default:
17019: 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));
17020: REG16(AX) = 0x0000;
17021: REG8(BL) = 0x80; // function not implemented
17022: break;
17023: }
17024: } catch(...) {
1.1.1.19 root 17025: REG16(AX) = 0x0000;
1.1.1.28 root 17026: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 17027: }
17028: break;
17029: #endif
17030: case 0x6a:
1.1.1.24 root 17031: // irq12 (mouse)
17032: mouse_push_ax = REG16(AX);
17033: mouse_push_bx = REG16(BX);
17034: mouse_push_cx = REG16(CX);
17035: mouse_push_dx = REG16(DX);
17036: mouse_push_si = REG16(SI);
17037: mouse_push_di = REG16(DI);
17038:
1.1.1.43 root 17039: if(mouse.status_irq && mouse.call_addr.dw) {
1.1.1.24 root 17040: REG16(AX) = mouse.status_irq;
17041: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 17042: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
17043: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
1.1.1.24 root 17044: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
17045: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
17046:
1.1.1.49 root 17047: mem[DUMMY_TOP + 0x02] = 0x9a; // call far
17048: mem[DUMMY_TOP + 0x03] = mouse.call_addr.w.l & 0xff;
17049: mem[DUMMY_TOP + 0x04] = mouse.call_addr.w.l >> 8;
17050: mem[DUMMY_TOP + 0x05] = mouse.call_addr.w.h & 0xff;
17051: mem[DUMMY_TOP + 0x06] = mouse.call_addr.w.h >> 8;
1.1.1.43 root 17052: break;
1.1.1.24 root 17053: }
1.1.1.43 root 17054: for(int i = 0; i < 8; i++) {
17055: if((mouse.status_irq_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
17056: REG16(AX) = mouse.status_irq_alt;
17057: REG16(BX) = mouse.get_buttons();
17058: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
17059: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
17060: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
17061: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
17062:
1.1.1.49 root 17063: mem[DUMMY_TOP + 0x02] = 0x9a; // call far
17064: mem[DUMMY_TOP + 0x03] = mouse.call_addr_alt[i].w.l & 0xff;
17065: mem[DUMMY_TOP + 0x04] = mouse.call_addr_alt[i].w.l >> 8;
17066: mem[DUMMY_TOP + 0x05] = mouse.call_addr_alt[i].w.h & 0xff;
17067: mem[DUMMY_TOP + 0x06] = mouse.call_addr_alt[i].w.h >> 8;
1.1.1.43 root 17068: break;
17069: }
17070: }
17071: // invalid call addr :-(
1.1.1.49 root 17072: mem[DUMMY_TOP + 0x02] = 0x90; // nop
17073: mem[DUMMY_TOP + 0x03] = 0x90; // nop
17074: mem[DUMMY_TOP + 0x04] = 0x90; // nop
17075: mem[DUMMY_TOP + 0x05] = 0x90; // nop
17076: mem[DUMMY_TOP + 0x06] = 0x90; // nop
1.1.1.24 root 17077: break;
17078: case 0x6b:
17079: // end of irq12 (mouse)
17080: REG16(AX) = mouse_push_ax;
17081: REG16(BX) = mouse_push_bx;
17082: REG16(CX) = mouse_push_cx;
17083: REG16(DX) = mouse_push_dx;
17084: REG16(SI) = mouse_push_si;
17085: REG16(DI) = mouse_push_di;
17086:
17087: // EOI
17088: if((pic[1].isr &= ~(1 << 4)) == 0) {
17089: pic[0].isr &= ~(1 << 2); // master
17090: }
17091: pic_update();
17092: break;
17093: case 0x6c:
1.1.1.19 root 17094: // dummy interrupt for case map routine pointed in the country info
17095: if(REG8(AL) >= 0x80) {
17096: char tmp[2] = {0};
17097: tmp[0] = REG8(AL);
17098: my_strupr(tmp);
17099: REG8(AL) = tmp[0];
17100: }
17101: break;
1.1.1.27 root 17102: case 0x6d:
17103: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
17104: REG8(AL) = 0x86; // not supported
17105: m_CF = 1;
17106: break;
1.1.1.32 root 17107: case 0x6e:
17108: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
17109: {
17110: UINT16 code = REG16(AX);
17111: if(code & 0xf0) {
17112: code = (code & 7) | ((code & 0x10) >> 1);
17113: }
17114: for(int i = 0; i < array_length(param_error_table); i++) {
17115: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
17116: const char *message = NULL;
17117: if(active_code_page == 932) {
17118: message = param_error_table[i].message_japanese;
17119: }
17120: if(message == NULL) {
17121: message = param_error_table[i].message_english;
17122: }
17123: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
17124: strcpy((char *)(mem + WORK_TOP + 1), message);
17125:
17126: SREG(ES) = WORK_TOP >> 4;
17127: i386_load_segment_descriptor(ES);
17128: REG16(DI) = 0x0000;
17129: break;
17130: }
17131: }
17132: }
17133: break;
1.1.1.49 root 17134: case 0x6f:
17135: // dummy interrupt for end of alter page map and call
17136: {
17137: UINT16 handles[4], pages[4];
17138:
17139: // pop old mapping data in new mapping
17140: for(int i = 0; i < 4; i++) {
17141: pages [3 - i] = i386_pop16();
17142: handles[3 - i] = i386_pop16();
17143: }
17144:
17145: // restore old mapping
17146: for(int i = 0; i < 4; i++) {
17147: UINT16 handle = handles[i];
17148: UINT16 page = pages [i];
17149:
17150: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
17151: ems_map_page(i, handle, page);
17152: } else {
17153: ems_unmap_page(i);
17154: }
17155: }
17156: // do ret_far (pop cs/ip) in old mapping
17157: }
17158: break;
1.1.1.8 root 17159: case 0x70:
17160: case 0x71:
17161: case 0x72:
17162: case 0x73:
17163: case 0x74:
17164: case 0x75:
17165: case 0x76:
17166: case 0x77:
17167: // EOI
17168: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
17169: pic[0].isr &= ~(1 << 2); // master
17170: }
17171: pic_update();
17172: break;
1.1 root 17173: default:
1.1.1.22 root 17174: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 17175: break;
17176: }
17177:
17178: // update cursor position
17179: if(cursor_moved) {
1.1.1.36 root 17180: pcbios_update_cursor_position();
1.1 root 17181: cursor_moved = false;
17182: }
17183: }
17184:
17185: // init
17186:
17187: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
17188: {
17189: // init file handler
17190: memset(file_handler, 0, sizeof(file_handler));
17191: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
17192: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
17193: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 17194: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 17195: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 17196: #else
17197: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
17198: #endif
17199: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 17200: }
1.1.1.21 root 17201: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.45 root 17202: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
17203: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1
1.1.1.21 root 17204: }
1.1 root 17205: _dup2(0, DUP_STDIN);
17206: _dup2(1, DUP_STDOUT);
17207: _dup2(2, DUP_STDERR);
1.1.1.21 root 17208: _dup2(3, DUP_STDAUX);
17209: _dup2(4, DUP_STDPRN);
1.1 root 17210:
1.1.1.24 root 17211: // init mouse
17212: memset(&mouse, 0, sizeof(mouse));
1.1.1.34 root 17213: mouse.enabled = true; // from DOSBox
17214: mouse.hidden = 1; // hidden in default ???
17215: mouse.old_hidden = 1; // from DOSBox
17216: mouse.max_position.x = 8 * (scr_width - 1);
17217: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 17218: mouse.mickey.x = 8;
17219: mouse.mickey.y = 16;
17220:
1.1.1.26 root 17221: #ifdef SUPPORT_XMS
17222: // init xms
17223: msdos_xms_init();
17224: #endif
17225:
1.1 root 17226: // init process
17227: memset(process, 0, sizeof(process));
17228:
1.1.1.13 root 17229: // init dtainfo
17230: msdos_dta_info_init();
17231:
1.1 root 17232: // init memory
17233: memset(mem, 0, sizeof(mem));
17234:
17235: // bios data area
1.1.1.23 root 17236: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 17237: CONSOLE_SCREEN_BUFFER_INFO csbi;
17238: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 17239: CONSOLE_FONT_INFO cfi;
17240: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
17241:
17242: int regen = min(scr_width * scr_height * 2, 0x8000);
17243: text_vram_top_address = TEXT_VRAM_TOP;
17244: text_vram_end_address = text_vram_top_address + regen;
17245: shadow_buffer_top_address = SHADOW_BUF_TOP;
17246: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1.1.51 root 17247: cursor_position_address = 0x450 + mem[0x462] * 2;
1.1.1.14 root 17248:
17249: if(regen > 0x4000) {
17250: regen = 0x8000;
17251: vram_pages = 1;
17252: } else if(regen > 0x2000) {
17253: regen = 0x4000;
17254: vram_pages = 2;
17255: } else if(regen > 0x1000) {
17256: regen = 0x2000;
17257: vram_pages = 4;
17258: } else {
17259: regen = 0x1000;
17260: vram_pages = 8;
17261: }
1.1 root 17262:
1.1.1.25 root 17263: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
17264: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 17265: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
17266: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 17267: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.37 root 17268: *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
17269: *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32 root 17270: #ifdef EXT_BIOS_TOP
1.1.1.25 root 17271: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32 root 17272: #endif
1.1.1.26 root 17273: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1.1.33 root 17274: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
1.1.1.41 root 17275: *(UINT16 *)(mem + 0x41a) = 0x1e;
17276: *(UINT16 *)(mem + 0x41c) = 0x1e;
1.1 root 17277: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 17278: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
17279: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 17280: *(UINT16 *)(mem + 0x44e) = 0;
17281: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 17282: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 17283: *(UINT8 *)(mem + 0x460) = 7;
17284: *(UINT8 *)(mem + 0x461) = 7;
17285: *(UINT8 *)(mem + 0x462) = 0;
17286: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 17287: *(UINT8 *)(mem + 0x465) = 0x09;
17288: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.40 root 17289: *(UINT16 *)(mem + 0x472) = 0x4321; // preserve memory in cpu reset
1.1.1.41 root 17290: *(UINT16 *)(mem + 0x480) = 0x1e;
17291: *(UINT16 *)(mem + 0x482) = 0x3e;
1.1.1.14 root 17292: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
17293: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
17294: *(UINT8 *)(mem + 0x487) = 0x60;
17295: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32 root 17296: #ifdef EXT_BIOS_TOP
1.1.1.25 root 17297: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32 root 17298: #endif
1.1.1.14 root 17299:
17300: // initial screen
17301: SMALL_RECT rect;
17302: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
17303: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
17304: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
17305: for(int x = 0; x < scr_width; x++) {
17306: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
17307: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
17308: }
17309: }
1.1 root 17310:
1.1.1.19 root 17311: // init mcb
1.1 root 17312: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 17313:
17314: // iret table
17315: // note: int 2eh vector should address the routine in command.com,
17316: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
17317: // so move iret table into allocated memory block
17318: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
1.1.1.33 root 17319: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, IRET_SIZE >> 4);
1.1.1.19 root 17320: IRET_TOP = seg << 4;
17321: seg += IRET_SIZE >> 4;
1.1.1.25 root 17322: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 17323:
17324: // dummy xms/ems device
1.1.1.33 root 17325: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
1.1.1.19 root 17326: XMS_TOP = seg << 4;
17327: seg += XMS_SIZE >> 4;
17328:
17329: // environment
1.1.1.33 root 17330: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
1.1 root 17331: int env_seg = seg;
17332: int ofs = 0;
1.1.1.32 root 17333: char env_append[ENV_SIZE] = {0}, append_added = 0;
17334: char comspec_added = 0;
1.1.1.33 root 17335: char lastdrive_added = 0;
1.1.1.32 root 17336: char env_msdos_path[ENV_SIZE] = {0};
17337: char env_path[ENV_SIZE] = {0}, path_added = 0;
1.1.1.33 root 17338: char prompt_added = 0;
1.1.1.32 root 17339: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
1.1.1.33 root 17340: char tz_added = 0;
1.1.1.45 root 17341: const char *path, *short_path;
1.1.1.32 root 17342:
17343: if((path = getenv("MSDOS_APPEND")) != NULL) {
17344: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17345: strcpy(env_append, short_path);
17346: }
17347: }
17348: if((path = getenv("APPEND")) != NULL) {
17349: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17350: if(env_append[0] != '\0') {
17351: strcat(env_append, ";");
17352: }
17353: strcat(env_append, short_path);
17354: }
17355: }
17356:
17357: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
17358: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17359: strcpy(comspec_path, short_path);
17360: }
17361: }
17362: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
17363: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17364: strcpy(comspec_path, short_path);
17365: }
17366: }
1.1 root 17367:
1.1.1.28 root 17368: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32 root 17369: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17370: strcpy(env_msdos_path, short_path);
17371: strcpy(env_path, short_path);
1.1.1.14 root 17372: }
17373: }
1.1.1.28 root 17374: if((path = getenv("PATH")) != NULL) {
1.1.1.32 root 17375: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17376: if(env_path[0] != '\0') {
17377: strcat(env_path, ";");
17378: }
17379: strcat(env_path, short_path);
1.1.1.9 root 17380: }
17381: }
1.1.1.32 root 17382:
17383: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
17384: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 17385: }
1.1.1.32 root 17386: for(int i = 0; i < 4; i++) {
17387: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
17388: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
17389: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17390: strcpy(env_temp, short_path);
17391: break;
17392: }
17393: }
1.1.1.24 root 17394: }
1.1.1.32 root 17395:
1.1.1.9 root 17396: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 17397: // lower to upper
1.1.1.28 root 17398: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 17399: strcpy(tmp, *p);
17400: for(int i = 0;; i++) {
17401: if(tmp[i] == '=') {
17402: tmp[i] = '\0';
17403: sprintf(name, ";%s;", tmp);
1.1.1.25 root 17404: my_strupr(name);
1.1 root 17405: tmp[i] = '=';
17406: break;
17407: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 17408: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 17409: }
17410: }
1.1.1.33 root 17411: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
17412: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
17413: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 17414: // ignore non standard environments
17415: } else {
1.1.1.33 root 17416: if(strncmp(tmp, "APPEND=", 7) == 0) {
1.1.1.32 root 17417: if(env_append[0] != '\0') {
17418: sprintf(tmp, "APPEND=%s", env_append);
17419: } else {
17420: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
17421: }
17422: append_added = 1;
17423: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 17424: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32 root 17425: comspec_added = 1;
1.1.1.33 root 17426: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
17427: char *env = getenv("MSDOS_LASTDRIVE");
17428: if(env != NULL) {
17429: sprintf(tmp, "LASTDRIVE=%s", env);
17430: }
17431: lastdrive_added = 1;
17432: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
1.1.1.28 root 17433: if(env_msdos_path[0] != '\0') {
17434: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
17435: } else {
17436: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
17437: }
1.1.1.33 root 17438: } else if(strncmp(tmp, "PATH=", 5) == 0) {
1.1.1.28 root 17439: if(env_path[0] != '\0') {
17440: sprintf(tmp, "PATH=%s", env_path);
17441: } else {
17442: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
17443: }
1.1.1.32 root 17444: path_added = 1;
1.1.1.33 root 17445: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
17446: prompt_added = 1;
1.1.1.28 root 17447: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
17448: if(env_temp[0] != '\0') {
17449: sprintf(tmp, "TEMP=%s", env_temp);
17450: } else {
17451: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
17452: }
1.1.1.32 root 17453: temp_added = 1;
1.1.1.33 root 17454: } else if(strncmp(tmp, "TMP=", 4) == 0) {
1.1.1.28 root 17455: if(env_temp[0] != '\0') {
17456: sprintf(tmp, "TMP=%s", env_temp);
17457: } else {
17458: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 17459: }
1.1.1.32 root 17460: tmp_added = 1;
1.1.1.33 root 17461: } else if(strncmp(tmp, "TZ=", 3) == 0) {
17462: char *env = getenv("MSDOS_TZ");
17463: if(env != NULL) {
17464: sprintf(tmp, "TZ=%s", env);
17465: }
17466: tz_added = 1;
1.1 root 17467: }
17468: int len = strlen(tmp);
1.1.1.14 root 17469: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 17470: fatalerror("too many environments\n");
17471: }
17472: memcpy(mem + (seg << 4) + ofs, tmp, len);
17473: ofs += len + 1;
17474: }
17475: }
1.1.1.32 root 17476: if(!append_added && env_append[0] != '\0') {
17477: #define SET_ENV(name, value) { \
17478: char tmp[ENV_SIZE]; \
17479: sprintf(tmp, "%s=%s", name, value); \
17480: int len = strlen(tmp); \
17481: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
17482: fatalerror("too many environments\n"); \
17483: } \
17484: memcpy(mem + (seg << 4) + ofs, tmp, len); \
17485: ofs += len + 1; \
17486: }
17487: SET_ENV("APPEND", env_append);
17488: }
17489: if(!comspec_added) {
17490: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
17491: }
1.1.1.33 root 17492: if(!lastdrive_added) {
17493: SET_ENV("LASTDRIVE", "Z");
17494: }
1.1.1.32 root 17495: if(!path_added) {
17496: SET_ENV("PATH", env_path);
17497: }
1.1.1.33 root 17498: if(!prompt_added) {
17499: SET_ENV("PROMPT", "$P$G");
17500: }
1.1.1.32 root 17501: if(!temp_added) {
17502: SET_ENV("TEMP", env_temp);
17503: }
17504: if(!tmp_added) {
17505: SET_ENV("TMP", env_temp);
17506: }
1.1.1.33 root 17507: if(!tz_added) {
17508: TIME_ZONE_INFORMATION tzi;
17509: HKEY hKey, hSubKey;
17510: char tzi_std_name[64];
17511: char tz_std[8] = "GMT";
17512: char tz_dlt[8] = "GST";
17513: char tz_value[32];
17514:
17515: // timezone name from GetTimeZoneInformation may not be english
17516: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
17517: setlocale(LC_CTYPE, "");
17518: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
17519:
17520: // get english timezone name from registry
17521: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
17522: for(DWORD i = 0; !tz_added; i++) {
17523: char reg_name[256], sub_key[1024], std_name[256];
17524: DWORD size;
17525: FILETIME ftTime;
17526: LONG result = RegEnumKeyEx(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
17527:
17528: if(result == ERROR_SUCCESS) {
17529: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
17530: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
17531: if(RegQueryValueEx(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
17532: // search english timezone name from table
1.1.1.37 root 17533: if(strcmp(std_name, tzi_std_name) == 0) {
1.1.1.33 root 17534: for(int j = 0; j < array_length(tz_table); j++) {
17535: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
17536: if(tz_table[j].std != NULL) {
17537: strcpy(tz_std, tz_table[j].std);
17538: }
17539: if(tz_table[j].dlt != NULL) {
17540: strcpy(tz_dlt, tz_table[j].dlt);
17541: }
17542: tz_added = 1;
17543: break;
17544: }
17545: }
17546: }
17547: }
17548: RegCloseKey(hSubKey);
17549: }
17550: } else if(result == ERROR_NO_MORE_ITEMS) {
17551: break;
17552: }
17553: }
17554: RegCloseKey(hKey);
17555: }
17556: if((tzi.Bias % 60) != 0) {
17557: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
17558: } else {
17559: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
17560: }
17561: if(daylight) {
17562: strcat(tz_value, tz_dlt);
17563: }
17564: SET_ENV("TZ", tz_value);
17565: }
1.1 root 17566: seg += (ENV_SIZE >> 4);
17567:
17568: // psp
1.1.1.33 root 17569: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
1.1 root 17570: current_psp = seg;
1.1.1.35 root 17571: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
17572: psp->parent_psp = current_psp;
1.1 root 17573: seg += (PSP_SIZE >> 4);
17574:
1.1.1.19 root 17575: // first free mcb in conventional memory
1.1.1.33 root 17576: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 17577: first_mcb = seg;
17578:
1.1.1.19 root 17579: // dummy mcb to link to umb
1.1.1.33 root 17580: #if 0
1.1.1.39 root 17581: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); // link umb
1.1.1.33 root 17582: #else
1.1.1.39 root 17583: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); // unlink umb
1.1.1.33 root 17584: #endif
1.1.1.19 root 17585:
17586: // first free mcb in upper memory block
1.1.1.8 root 17587: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 17588:
1.1.1.29 root 17589: #ifdef SUPPORT_HMA
17590: // first free mcb in high memory area
17591: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
17592: #endif
17593:
1.1.1.26 root 17594: // interrupt vector
17595: for(int i = 0; i < 0x80; i++) {
17596: *(UINT16 *)(mem + 4 * i + 0) = i;
17597: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
17598: }
1.1.1.49 root 17599: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffc:0018 irq0 (system timer)
17600: *(UINT16 *)(mem + 4 * 0x08 + 2) = DUMMY_TOP >> 4;
1.1.1.26 root 17601: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
17602: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
17603: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
17604: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
1.1.1.49 root 17605: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffc:0000 irq12 (mouse)
17606: *(UINT16 *)(mem + 4 * 0x74 + 2) = DUMMY_TOP >> 4;
1.1.1.26 root 17607:
1.1.1.29 root 17608: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 17609: static const struct {
17610: UINT16 attributes;
17611: char *dev_name;
17612: } dummy_devices[] = {
17613: {0x8013, "CON "},
17614: {0x8000, "AUX "},
17615: {0xa0c0, "PRN "},
17616: {0x8008, "CLOCK$ "},
17617: {0x8000, "COM1 "},
17618: {0xa0c0, "LPT1 "},
17619: {0xa0c0, "LPT2 "},
17620: {0xa0c0, "LPT3 "},
17621: {0x8000, "COM2 "},
17622: {0x8000, "COM3 "},
17623: {0x8000, "COM4 "},
1.1.1.30 root 17624: // {0xc000, "CONFIG$ "},
17625: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 17626: };
17627: static const UINT8 dummy_device_routine[] = {
17628: // from NUL device of Windows 98 SE
17629: // or word ptr ES:[BX+03],0100
17630: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
17631: // retf
17632: 0xcb,
17633: };
1.1.1.29 root 17634: device_t *last = NULL;
1.1.1.32 root 17635: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 17636: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 17637: device->next_driver.w.l = 22 + 18 * (i + 1);
17638: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 17639: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 17640: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
17641: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 17642: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 17643: last = device;
17644: }
17645: if(last != NULL) {
17646: last->next_driver.w.l = 0;
17647: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 17648: }
1.1.1.29 root 17649: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 17650:
1.1.1.25 root 17651: // dos info
17652: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
17653: dos_info->magic_word = 1;
17654: dos_info->first_mcb = MEMORY_TOP >> 4;
17655: dos_info->first_dpb.w.l = 0;
17656: dos_info->first_dpb.w.h = DPB_TOP >> 4;
17657: dos_info->first_sft.w.l = 0;
17658: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.41 root 17659: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 4th device in IO.SYS
1.1.1.25 root 17660: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 17661: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 17662: dos_info->con_device.w.h = DEVICE_TOP >> 4;
17663: dos_info->max_sector_len = 512;
17664: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
17665: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
17666: dos_info->cds.w.l = 0;
17667: dos_info->cds.w.h = CDS_TOP >> 4;
17668: dos_info->fcb_table.w.l = 0;
17669: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
17670: dos_info->last_drive = 'Z' - 'A' + 1;
17671: dos_info->buffers_x = 20;
17672: dos_info->buffers_y = 0;
17673: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 17674: dos_info->nul_device.next_driver.w.l = 22;
17675: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 17676: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 17677: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
17678: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 17679: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
17680: dos_info->disk_buf_heads.w.l = 0;
17681: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.39 root 17682: dos_info->umb_linked = (((mcb_t *)(mem + MEMORY_END - 16))->mz == 'M' ? 0x01 : 0x00);
1.1.1.25 root 17683: dos_info->first_umb_fcb = UMB_TOP >> 4;
17684: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 17685: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 17686:
17687: char *env;
17688: if((env = getenv("LASTDRIVE")) != NULL) {
17689: if(env[0] >= 'A' && env[0] <= 'Z') {
17690: dos_info->last_drive = env[0] - 'A' + 1;
17691: } else if(env[0] >= 'a' && env[0] <= 'z') {
17692: dos_info->last_drive = env[0] - 'a' + 1;
17693: }
17694: }
17695: if((env = getenv("windir")) != NULL) {
17696: if(env[0] >= 'A' && env[0] <= 'Z') {
17697: dos_info->boot_drive = env[0] - 'A' + 1;
17698: } else if(env[0] >= 'a' && env[0] <= 'z') {
17699: dos_info->boot_drive = env[0] - 'a' + 1;
17700: }
17701: }
17702: #if defined(HAS_I386)
17703: dos_info->i386_or_later = 1;
17704: #else
17705: dos_info->i386_or_later = 0;
17706: #endif
17707: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
17708:
1.1.1.27 root 17709: // ems (int 67h) and xms
1.1.1.25 root 17710: device_t *xms_device = (device_t *)(mem + XMS_TOP);
17711: xms_device->next_driver.w.l = 0xffff;
17712: xms_device->next_driver.w.h = 0xffff;
17713: xms_device->attributes = 0xc000;
1.1.1.29 root 17714: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
17715: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 17716: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
17717:
1.1.1.26 root 17718: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
17719: mem[XMS_TOP + 0x13] = 0x68;
17720: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 17721: #ifdef SUPPORT_XMS
17722: if(support_xms) {
1.1.1.26 root 17723: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
17724: mem[XMS_TOP + 0x16] = 0x69;
17725: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 17726: } else
17727: #endif
1.1.1.26 root 17728: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 17729: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 17730:
1.1.1.26 root 17731: // irq12 routine (mouse)
1.1.1.49 root 17732: mem[DUMMY_TOP + 0x00] = 0xcd; // int 6ah (dummy)
17733: mem[DUMMY_TOP + 0x01] = 0x6a;
17734: mem[DUMMY_TOP + 0x02] = 0x9a; // call far mouse
17735: mem[DUMMY_TOP + 0x03] = 0xff;
17736: mem[DUMMY_TOP + 0x04] = 0xff;
17737: mem[DUMMY_TOP + 0x05] = 0xff;
17738: mem[DUMMY_TOP + 0x06] = 0xff;
17739: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy)
17740: mem[DUMMY_TOP + 0x08] = 0x6b;
17741: mem[DUMMY_TOP + 0x09] = 0xcf; // iret
1.1.1.24 root 17742:
1.1.1.27 root 17743: // case map routine
1.1.1.49 root 17744: mem[DUMMY_TOP + 0x0a] = 0xcd; // int 6ch (dummy)
17745: mem[DUMMY_TOP + 0x0b] = 0x6c;
17746: mem[DUMMY_TOP + 0x0c] = 0xcb; // retf
1.1.1.27 root 17747:
17748: // font read routine
1.1.1.49 root 17749: mem[DUMMY_TOP + 0x0d] = 0xcd; // int 6dh (dummy)
17750: mem[DUMMY_TOP + 0x0e] = 0x6d;
17751: mem[DUMMY_TOP + 0x0f] = 0xcb; // retf
1.1.1.19 root 17752:
1.1.1.32 root 17753: // error message read routine
1.1.1.49 root 17754: mem[DUMMY_TOP + 0x10] = 0xcd; // int 6eh (dummy)
17755: mem[DUMMY_TOP + 0x11] = 0x6e;
17756: mem[DUMMY_TOP + 0x12] = 0xcb; // retf
1.1.1.32 root 17757:
1.1.1.35 root 17758: // dummy loop to wait BIOS/DOS service is done
1.1.1.49 root 17759: mem[DUMMY_TOP + 0x13] = 0xe6; // out f7h, al
17760: mem[DUMMY_TOP + 0x14] = 0xf7;
17761: mem[DUMMY_TOP + 0x15] = 0x78; // js/jns -4
17762: mem[DUMMY_TOP + 0x16] = 0xfc;
17763: mem[DUMMY_TOP + 0x17] = 0xcb; // retf
1.1.1.35 root 17764:
1.1.1.50 root 17765: // irq0 routine (system timer)
1.1.1.49 root 17766: mem[DUMMY_TOP + 0x18] = 0xcd; // int 1ch
17767: mem[DUMMY_TOP + 0x19] = 0x1c;
17768: mem[DUMMY_TOP + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008
17769: mem[DUMMY_TOP + 0x1b] = 0x08;
17770: mem[DUMMY_TOP + 0x1c] = 0x00;
17771: mem[DUMMY_TOP + 0x1d] = ((IRET_TOP >> 4) ) & 0xff;
17772: mem[DUMMY_TOP + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff;
17773:
17774: // alter page map and call routine
17775: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far
17776: mem[DUMMY_TOP + 0x20] = 0xff;
17777: mem[DUMMY_TOP + 0x21] = 0xff;
17778: mem[DUMMY_TOP + 0x22] = 0xff;
17779: mem[DUMMY_TOP + 0x23] = 0xff;
17780: mem[DUMMY_TOP + 0x24] = 0xcd; // int 6fh (dummy)
17781: mem[DUMMY_TOP + 0x25] = 0x6f;
17782: mem[DUMMY_TOP + 0x26] = 0xcb; // retf
1.1.1.14 root 17783:
1.1.1.50 root 17784: // call int 29h routine
17785: mem[DUMMY_TOP + 0x27] = 0xcd; // int 29h
17786: mem[DUMMY_TOP + 0x28] = 0x29;
17787: mem[DUMMY_TOP + 0x29] = 0xcb; // retf
17788:
1.1.1.26 root 17789: // boot routine
1.1.1.49 root 17790: mem[0xffff0 + 0x00] = 0xf4; // halt
17791: mem[0xffff0 + 0x05] = '0'; // rom date
17792: mem[0xffff0 + 0x06] = '2';
17793: mem[0xffff0 + 0x07] = '/';
17794: mem[0xffff0 + 0x08] = '2';
17795: mem[0xffff0 + 0x09] = '2';
17796: mem[0xffff0 + 0x0a] = '/';
17797: mem[0xffff0 + 0x0b] = '0';
17798: mem[0xffff0 + 0x0c] = '6';
17799: mem[0xffff0 + 0x0e] = 0xfc; // machine id
17800: mem[0xffff0 + 0x0f] = 0x00;
1.1.1.24 root 17801:
1.1 root 17802: // param block
17803: // + 0: param block (22bytes)
17804: // +24: fcb1/2 (20bytes)
17805: // +44: command tail (128bytes)
17806: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
17807: param->env_seg = 0;
17808: param->cmd_line.w.l = 44;
17809: param->cmd_line.w.h = (WORK_TOP >> 4);
17810: param->fcb1.w.l = 24;
17811: param->fcb1.w.h = (WORK_TOP >> 4);
17812: param->fcb2.w.l = 24;
17813: param->fcb2.w.h = (WORK_TOP >> 4);
17814:
17815: memset(mem + WORK_TOP + 24, 0x20, 20);
17816:
17817: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
17818: if(argc > 1) {
17819: sprintf(cmd_line->cmd, " %s", argv[1]);
17820: for(int i = 2; i < argc; i++) {
17821: char tmp[128];
17822: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
17823: strcpy(cmd_line->cmd, tmp);
17824: }
17825: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
17826: } else {
17827: cmd_line->len = 0;
17828: }
17829: cmd_line->cmd[cmd_line->len] = 0x0d;
17830:
17831: // system file table
1.1.1.21 root 17832: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
17833: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 17834:
1.1.1.19 root 17835: // disk buffer header (from DOSBox)
17836: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
17837: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
17838: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
17839: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
17840: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
17841:
1.1 root 17842: // fcb table
17843: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 17844: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 17845:
1.1.1.41 root 17846: // drive parameter block
1.1.1.42 root 17847: for(int i = 0; i < 2; i++) {
1.1.1.43 root 17848: // may be a floppy drive
1.1.1.44 root 17849: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * i);
17850: sprintf(cds->path_name, "%c:\\", 'A' + i);
17851: cds->drive_attrib = 0x4000; // physical drive
17852: cds->dpb_ptr.w.l = sizeof(dpb_t) * i;
17853: cds->dpb_ptr.w.h = DPB_TOP >> 4;
17854: cds->word_1 = cds->word_2 = cds->word_3 = 0xffff;
17855: cds->bs_offset = 2;
17856:
1.1.1.41 root 17857: dpb_t *dpb = (dpb_t *)(mem + DPB_TOP + sizeof(dpb_t) * i);
17858: dpb->drive_num = i;
17859: dpb->unit_num = i;
1.1.1.43 root 17860: dpb->next_dpb_ofs = /*(i == 25) ? 0xffff : */sizeof(dpb_t) * (i + 1);
17861: dpb->next_dpb_seg = /*(i == 25) ? 0xffff : */DPB_TOP >> 4;
1.1.1.42 root 17862: }
17863: for(int i = 2; i < 26; i++) {
1.1.1.44 root 17864: msdos_cds_update(i);
1.1.1.42 root 17865: UINT16 seg, ofs;
17866: msdos_drive_param_block_update(i, &seg, &ofs, 1);
1.1.1.41 root 17867: }
17868:
1.1.1.17 root 17869: // nls stuff
17870: msdos_nls_tables_init();
1.1 root 17871:
17872: // execute command
1.1.1.28 root 17873: try {
1.1.1.52 root 17874: if(msdos_process_exec(argv[0], param, 0, true)) {
1.1.1.28 root 17875: fatalerror("'%s' not found\n", argv[0]);
17876: }
17877: } catch(...) {
17878: // we should not reach here :-(
17879: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 17880: }
17881: retval = 0;
17882: return(0);
17883: }
17884:
17885: #define remove_std_file(path) { \
17886: int fd = _open(path, _O_RDONLY | _O_BINARY); \
17887: if(fd != -1) { \
17888: _lseek(fd, 0, SEEK_END); \
17889: int size = _tell(fd); \
17890: _close(fd); \
17891: if(size == 0) { \
17892: remove(path); \
17893: } \
17894: } \
17895: }
17896:
17897: void msdos_finish()
17898: {
17899: for(int i = 0; i < MAX_FILES; i++) {
17900: if(file_handler[i].valid) {
17901: _close(i);
17902: }
17903: }
1.1.1.21 root 17904: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 17905: remove_std_file("stdaux.txt");
1.1.1.21 root 17906: #endif
1.1.1.30 root 17907: #ifdef SUPPORT_XMS
17908: msdos_xms_finish();
17909: #endif
1.1 root 17910: msdos_dbcs_table_finish();
17911: }
17912:
17913: /* ----------------------------------------------------------------------------
17914: PC/AT hardware emulation
17915: ---------------------------------------------------------------------------- */
17916:
17917: void hardware_init()
17918: {
1.1.1.3 root 17919: CPU_INIT_CALL(CPU_MODEL);
1.1 root 17920: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 17921: m_IF = 1;
1.1.1.3 root 17922: #if defined(HAS_I386)
1.1 root 17923: cpu_type = (REG32(EDX) >> 8) & 0x0f;
17924: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 17925: #endif
17926: i386_set_a20_line(0);
1.1.1.14 root 17927:
1.1.1.19 root 17928: ems_init();
1.1.1.25 root 17929: dma_init();
1.1 root 17930: pic_init();
1.1.1.25 root 17931: pio_init();
1.1.1.8 root 17932: #ifdef PIT_ALWAYS_RUNNING
17933: pit_init();
17934: #else
1.1 root 17935: pit_active = 0;
17936: #endif
1.1.1.25 root 17937: sio_init();
1.1.1.8 root 17938: cmos_init();
17939: kbd_init();
1.1 root 17940: }
17941:
1.1.1.10 root 17942: void hardware_finish()
17943: {
17944: #if defined(HAS_I386)
17945: vtlb_free(m_vtlb);
17946: #endif
1.1.1.19 root 17947: ems_finish();
1.1.1.37 root 17948: pio_finish();
1.1.1.25 root 17949: sio_finish();
1.1.1.10 root 17950: }
17951:
1.1.1.28 root 17952: void hardware_release()
17953: {
17954: // release hardware resources when this program will be terminated abnormally
17955: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 17956: if(fp_debug_log != NULL) {
17957: fclose(fp_debug_log);
17958: fp_debug_log = NULL;
1.1.1.28 root 17959: }
17960: #endif
17961: #if defined(HAS_I386)
17962: vtlb_free(m_vtlb);
17963: #endif
17964: ems_release();
1.1.1.37 root 17965: pio_release();
1.1.1.28 root 17966: sio_release();
17967: }
17968:
1.1 root 17969: void hardware_run()
17970: {
1.1.1.22 root 17971: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 17972: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.33 root 17973: fp_debug_log = fopen("debug.log", "w");
1.1.1.22 root 17974: #endif
1.1.1.51 root 17975: #ifdef USE_DEBUGGER
17976: m_int_num = -1;
17977: #endif
1.1.1.3 root 17978: while(!m_halted) {
1.1.1.50 root 17979: hardware_run_cpu();
1.1 root 17980: }
1.1.1.22 root 17981: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 17982: if(fp_debug_log != NULL) {
17983: fclose(fp_debug_log);
17984: fp_debug_log = NULL;
1.1.1.28 root 17985: }
1.1.1.22 root 17986: #endif
1.1 root 17987: }
17988:
1.1.1.50 root 17989: inline void hardware_run_cpu()
17990: {
17991: #if defined(HAS_I386)
17992: CPU_EXECUTE_CALL(i386);
17993: if(m_eip != m_prev_eip) {
17994: idle_ops++;
17995: }
17996: #else
17997: CPU_EXECUTE_CALL(CPU_MODEL);
17998: if(m_pc != m_prevpc) {
17999: idle_ops++;
18000: }
18001: #endif
18002: #ifdef USE_DEBUGGER
18003: // Disallow reentering CPU_EXECUTE() in msdos_syscall()
18004: if(m_int_num >= 0) {
18005: unsigned num = (unsigned)m_int_num;
18006: m_int_num = -1;
18007: msdos_syscall(num);
18008: }
18009: #endif
18010: if(++update_ops == UPDATE_OPS) {
18011: update_ops = 0;
18012: hardware_update();
18013: }
18014: }
18015:
1.1 root 18016: void hardware_update()
18017: {
1.1.1.8 root 18018: static UINT32 prev_time = 0;
18019: UINT32 cur_time = timeGetTime();
18020:
18021: if(prev_time != cur_time) {
18022: // update pit and raise irq0
18023: #ifndef PIT_ALWAYS_RUNNING
18024: if(pit_active)
18025: #endif
18026: {
18027: if(pit_run(0, cur_time)) {
18028: pic_req(0, 0, 1);
18029: }
18030: pit_run(1, cur_time);
18031: pit_run(2, cur_time);
18032: }
1.1.1.24 root 18033:
1.1.1.25 root 18034: // update sio and raise irq4/3
1.1.1.29 root 18035: for(int c = 0; c < 4; c++) {
1.1.1.25 root 18036: sio_update(c);
18037: }
18038:
1.1.1.24 root 18039: // update keyboard and mouse
1.1.1.14 root 18040: static UINT32 prev_tick = 0;
18041: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 18042:
1.1.1.14 root 18043: if(prev_tick != cur_tick) {
18044: // update keyboard flags
18045: UINT8 state;
1.1.1.24 root 18046: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
18047: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
18048: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
18049: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
18050: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
18051: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
18052: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
18053: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 18054: mem[0x417] = state;
18055: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
18056: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
18057: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
18058: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 18059: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
18060: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 18061: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
18062: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
18063: mem[0x418] = state;
18064:
1.1.1.24 root 18065: // update console input if needed
1.1.1.34 root 18066: if(!key_changed || mouse.hidden == 0) {
1.1.1.24 root 18067: update_console_input();
18068: }
18069:
18070: // raise irq1 if key is pressed/released
18071: if(key_changed) {
1.1.1.8 root 18072: pic_req(0, 1, 1);
1.1.1.24 root 18073: key_changed = false;
18074: }
18075:
18076: // raise irq12 if mouse status is changed
1.1.1.43 root 18077: if((mouse.status & mouse.call_mask) && mouse.call_addr.dw) {
18078: mouse.status_irq = mouse.status & mouse.call_mask;
18079: mouse.status_irq_alt = 0; // ???
1.1.1.24 root 18080: mouse.status &= ~mouse.call_mask;
1.1.1.43 root 18081: pic_req(1, 4, 1);
18082: } else {
18083: for(int i = 0; i < 8; i++) {
18084: if((mouse.status_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
18085: mouse.status_irq = 0; // ???
18086: mouse.status_irq_alt = 0;
18087: for(int j = 0; j < 8; j++) {
18088: if((mouse.status_alt & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
18089: mouse.status_irq_alt |= (1 << j);
18090: mouse.status_alt &= ~(1 << j);
18091: }
18092: }
18093: pic_req(1, 4, 1);
18094: break;
18095: }
18096: }
1.1.1.8 root 18097: }
1.1.1.24 root 18098:
1.1.1.14 root 18099: prev_tick = cur_tick;
1.1.1.8 root 18100: }
1.1.1.24 root 18101:
1.1.1.19 root 18102: // update daily timer counter
18103: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 18104:
1.1.1.8 root 18105: prev_time = cur_time;
1.1 root 18106: }
18107: }
18108:
1.1.1.19 root 18109: // ems
18110:
18111: void ems_init()
18112: {
18113: memset(ems_handles, 0, sizeof(ems_handles));
18114: memset(ems_pages, 0, sizeof(ems_pages));
18115: free_ems_pages = MAX_EMS_PAGES;
18116: }
18117:
18118: void ems_finish()
18119: {
1.1.1.28 root 18120: ems_release();
18121: }
18122:
18123: void ems_release()
18124: {
1.1.1.31 root 18125: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 18126: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 18127: free(ems_handles[i].buffer);
18128: ems_handles[i].buffer = NULL;
18129: }
18130: }
18131: }
18132:
18133: void ems_allocate_pages(int handle, int pages)
18134: {
18135: if(pages > 0) {
18136: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
18137: } else {
18138: ems_handles[handle].buffer = NULL;
18139: }
18140: ems_handles[handle].pages = pages;
18141: ems_handles[handle].allocated = true;
18142: free_ems_pages -= pages;
18143: }
18144:
18145: void ems_reallocate_pages(int handle, int pages)
18146: {
18147: if(ems_handles[handle].allocated) {
18148: if(ems_handles[handle].pages != pages) {
18149: UINT8 *new_buffer = NULL;
18150:
18151: if(pages > 0) {
18152: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
18153: }
1.1.1.32 root 18154: if(ems_handles[handle].buffer != NULL) {
18155: if(new_buffer != NULL) {
1.1.1.19 root 18156: if(pages > ems_handles[handle].pages) {
18157: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
18158: } else {
18159: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
18160: }
18161: }
18162: free(ems_handles[handle].buffer);
18163: ems_handles[handle].buffer = NULL;
18164: }
18165: free_ems_pages += ems_handles[handle].pages;
18166:
18167: ems_handles[handle].buffer = new_buffer;
18168: ems_handles[handle].pages = pages;
18169: free_ems_pages -= pages;
18170: }
18171: } else {
18172: ems_allocate_pages(handle, pages);
18173: }
18174: }
18175:
18176: void ems_release_pages(int handle)
18177: {
18178: if(ems_handles[handle].allocated) {
1.1.1.32 root 18179: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 18180: free(ems_handles[handle].buffer);
18181: ems_handles[handle].buffer = NULL;
18182: }
18183: free_ems_pages += ems_handles[handle].pages;
18184: ems_handles[handle].allocated = false;
18185: }
18186: }
18187:
18188: void ems_map_page(int physical, int handle, int logical)
18189: {
18190: if(ems_pages[physical].mapped) {
18191: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
18192: return;
18193: }
18194: ems_unmap_page(physical);
18195: }
1.1.1.32 root 18196: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 18197: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
18198: }
18199: ems_pages[physical].handle = handle;
18200: ems_pages[physical].page = logical;
18201: ems_pages[physical].mapped = true;
18202: }
18203:
18204: void ems_unmap_page(int physical)
18205: {
18206: if(ems_pages[physical].mapped) {
18207: int handle = ems_pages[physical].handle;
18208: int logical = ems_pages[physical].page;
18209:
1.1.1.32 root 18210: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 18211: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
18212: }
18213: ems_pages[physical].mapped = false;
18214: }
18215: }
18216:
1.1.1.25 root 18217: // dma
1.1 root 18218:
1.1.1.25 root 18219: void dma_init()
1.1 root 18220: {
1.1.1.26 root 18221: memset(dma, 0, sizeof(dma));
1.1.1.25 root 18222: for(int c = 0; c < 2; c++) {
1.1.1.26 root 18223: // for(int ch = 0; ch < 4; ch++) {
18224: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
18225: // }
1.1.1.25 root 18226: dma_reset(c);
18227: }
1.1 root 18228: }
18229:
1.1.1.25 root 18230: void dma_reset(int c)
1.1 root 18231: {
1.1.1.25 root 18232: dma[c].low_high = false;
18233: dma[c].cmd = dma[c].req = dma[c].tc = 0;
18234: dma[c].mask = 0xff;
18235: }
18236:
18237: void dma_write(int c, UINT32 addr, UINT8 data)
18238: {
18239: int ch = (addr >> 1) & 3;
18240: UINT8 bit = 1 << (data & 3);
18241:
18242: switch(addr & 0x0f) {
18243: case 0x00: case 0x02: case 0x04: case 0x06:
18244: if(dma[c].low_high) {
18245: dma[c].ch[ch].bareg.b.h = data;
1.1 root 18246: } else {
1.1.1.25 root 18247: dma[c].ch[ch].bareg.b.l = data;
18248: }
18249: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
18250: dma[c].low_high = !dma[c].low_high;
18251: break;
18252: case 0x01: case 0x03: case 0x05: case 0x07:
18253: if(dma[c].low_high) {
18254: dma[c].ch[ch].bcreg.b.h = data;
18255: } else {
18256: dma[c].ch[ch].bcreg.b.l = data;
18257: }
18258: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
18259: dma[c].low_high = !dma[c].low_high;
18260: break;
18261: case 0x08:
18262: // command register
18263: dma[c].cmd = data;
18264: break;
18265: case 0x09:
18266: // dma[c].request register
18267: if(data & 4) {
18268: if(!(dma[c].req & bit)) {
18269: dma[c].req |= bit;
18270: // dma_run(c, ch);
18271: }
18272: } else {
18273: dma[c].req &= ~bit;
18274: }
18275: break;
18276: case 0x0a:
18277: // single mask register
18278: if(data & 4) {
18279: dma[c].mask |= bit;
18280: } else {
18281: dma[c].mask &= ~bit;
18282: }
18283: break;
18284: case 0x0b:
18285: // mode register
18286: dma[c].ch[data & 3].mode = data;
18287: break;
18288: case 0x0c:
18289: dma[c].low_high = false;
18290: break;
18291: case 0x0d:
18292: // clear master
18293: dma_reset(c);
18294: break;
18295: case 0x0e:
18296: // clear mask register
18297: dma[c].mask = 0;
18298: break;
18299: case 0x0f:
18300: // all mask register
18301: dma[c].mask = data & 0x0f;
18302: break;
18303: }
18304: }
18305:
18306: UINT8 dma_read(int c, UINT32 addr)
18307: {
18308: int ch = (addr >> 1) & 3;
18309: UINT8 val = 0xff;
18310:
18311: switch(addr & 0x0f) {
18312: case 0x00: case 0x02: case 0x04: case 0x06:
18313: if(dma[c].low_high) {
18314: val = dma[c].ch[ch].areg.b.h;
18315: } else {
18316: val = dma[c].ch[ch].areg.b.l;
18317: }
18318: dma[c].low_high = !dma[c].low_high;
18319: return(val);
18320: case 0x01: case 0x03: case 0x05: case 0x07:
18321: if(dma[c].low_high) {
18322: val = dma[c].ch[ch].creg.b.h;
18323: } else {
18324: val = dma[c].ch[ch].creg.b.l;
18325: }
18326: dma[c].low_high = !dma[c].low_high;
18327: return(val);
18328: case 0x08:
18329: // status register
18330: val = (dma[c].req << 4) | dma[c].tc;
18331: dma[c].tc = 0;
18332: return(val);
18333: case 0x0d:
1.1.1.26 root 18334: // temporary register (intel 82374 does not support)
1.1.1.25 root 18335: return(dma[c].tmp & 0xff);
1.1.1.26 root 18336: case 0x0f:
18337: // mask register (intel 82374 does support)
18338: return(dma[c].mask);
1.1.1.25 root 18339: }
18340: return(0xff);
18341: }
18342:
18343: void dma_page_write(int c, int ch, UINT8 data)
18344: {
18345: dma[c].ch[ch].pagereg = data;
18346: }
18347:
18348: UINT8 dma_page_read(int c, int ch)
18349: {
18350: return(dma[c].ch[ch].pagereg);
18351: }
18352:
18353: void dma_run(int c, int ch)
18354: {
18355: UINT8 bit = 1 << ch;
18356:
18357: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
18358: // execute dma
18359: while(dma[c].req & bit) {
18360: if(ch == 0 && (dma[c].cmd & 0x01)) {
18361: // memory -> memory
18362: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
18363: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
18364:
18365: if(c == 0) {
18366: dma[c].tmp = read_byte(saddr);
18367: write_byte(daddr, dma[c].tmp);
18368: } else {
18369: dma[c].tmp = read_word(saddr << 1);
18370: write_word(daddr << 1, dma[c].tmp);
18371: }
18372: if(!(dma[c].cmd & 0x02)) {
18373: if(dma[c].ch[0].mode & 0x20) {
18374: dma[c].ch[0].areg.w--;
18375: if(dma[c].ch[0].areg.w == 0xffff) {
18376: dma[c].ch[0].pagereg--;
18377: }
18378: } else {
18379: dma[c].ch[0].areg.w++;
18380: if(dma[c].ch[0].areg.w == 0) {
18381: dma[c].ch[0].pagereg++;
18382: }
18383: }
18384: }
18385: if(dma[c].ch[1].mode & 0x20) {
18386: dma[c].ch[1].areg.w--;
18387: if(dma[c].ch[1].areg.w == 0xffff) {
18388: dma[c].ch[1].pagereg--;
18389: }
18390: } else {
18391: dma[c].ch[1].areg.w++;
18392: if(dma[c].ch[1].areg.w == 0) {
18393: dma[c].ch[1].pagereg++;
18394: }
18395: }
18396:
18397: // check dma condition
18398: if(dma[c].ch[0].creg.w-- == 0) {
18399: if(dma[c].ch[0].mode & 0x10) {
18400: // self initialize
18401: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
18402: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
18403: } else {
18404: // dma[c].mask |= bit;
18405: }
18406: }
18407: if(dma[c].ch[1].creg.w-- == 0) {
18408: // terminal count
18409: if(dma[c].ch[1].mode & 0x10) {
18410: // self initialize
18411: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
18412: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
18413: } else {
18414: dma[c].mask |= bit;
18415: }
18416: dma[c].req &= ~bit;
18417: dma[c].tc |= bit;
18418: }
18419: } else {
18420: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
18421:
18422: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
18423: // verify
18424: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
18425: // io -> memory
18426: if(c == 0) {
18427: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
18428: write_byte(addr, dma[c].tmp);
18429: } else {
18430: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
18431: write_word(addr << 1, dma[c].tmp);
18432: }
18433: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
18434: // memory -> io
18435: if(c == 0) {
18436: dma[c].tmp = read_byte(addr);
18437: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
18438: } else {
18439: dma[c].tmp = read_word(addr << 1);
18440: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
18441: }
18442: }
18443: if(dma[c].ch[ch].mode & 0x20) {
18444: dma[c].ch[ch].areg.w--;
18445: if(dma[c].ch[ch].areg.w == 0xffff) {
18446: dma[c].ch[ch].pagereg--;
18447: }
18448: } else {
18449: dma[c].ch[ch].areg.w++;
18450: if(dma[c].ch[ch].areg.w == 0) {
18451: dma[c].ch[ch].pagereg++;
18452: }
18453: }
18454:
18455: // check dma condition
18456: if(dma[c].ch[ch].creg.w-- == 0) {
18457: // terminal count
18458: if(dma[c].ch[ch].mode & 0x10) {
18459: // self initialize
18460: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
18461: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
18462: } else {
18463: dma[c].mask |= bit;
18464: }
18465: dma[c].req &= ~bit;
18466: dma[c].tc |= bit;
18467: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
18468: // single mode
18469: break;
18470: }
18471: }
18472: }
18473: }
18474: }
18475:
18476: // pic
18477:
18478: void pic_init()
18479: {
18480: memset(pic, 0, sizeof(pic));
18481: pic[0].imr = pic[1].imr = 0xff;
18482:
18483: // from bochs bios
18484: pic_write(0, 0, 0x11); // icw1 = 11h
18485: pic_write(0, 1, 0x08); // icw2 = 08h
18486: pic_write(0, 1, 0x04); // icw3 = 04h
18487: pic_write(0, 1, 0x01); // icw4 = 01h
18488: pic_write(0, 1, 0xb8); // ocw1 = b8h
18489: pic_write(1, 0, 0x11); // icw1 = 11h
18490: pic_write(1, 1, 0x70); // icw2 = 70h
18491: pic_write(1, 1, 0x02); // icw3 = 02h
18492: pic_write(1, 1, 0x01); // icw4 = 01h
18493: }
18494:
18495: void pic_write(int c, UINT32 addr, UINT8 data)
18496: {
18497: if(addr & 1) {
18498: if(pic[c].icw2_r) {
18499: // icw2
18500: pic[c].icw2 = data;
18501: pic[c].icw2_r = 0;
18502: } else if(pic[c].icw3_r) {
18503: // icw3
18504: pic[c].icw3 = data;
18505: pic[c].icw3_r = 0;
18506: } else if(pic[c].icw4_r) {
18507: // icw4
18508: pic[c].icw4 = data;
18509: pic[c].icw4_r = 0;
18510: } else {
18511: // ocw1
1.1 root 18512: pic[c].imr = data;
18513: }
18514: } else {
18515: if(data & 0x10) {
18516: // icw1
18517: pic[c].icw1 = data;
18518: pic[c].icw2_r = 1;
18519: pic[c].icw3_r = (data & 2) ? 0 : 1;
18520: pic[c].icw4_r = data & 1;
18521: pic[c].irr = 0;
18522: pic[c].isr = 0;
18523: pic[c].imr = 0;
18524: pic[c].prio = 0;
18525: if(!(pic[c].icw1 & 1)) {
18526: pic[c].icw4 = 0;
18527: }
18528: pic[c].ocw3 = 0;
18529: } else if(data & 8) {
18530: // ocw3
18531: if(!(data & 2)) {
18532: data = (data & ~1) | (pic[c].ocw3 & 1);
18533: }
18534: if(!(data & 0x40)) {
18535: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
18536: }
18537: pic[c].ocw3 = data;
18538: } else {
18539: // ocw2
18540: int level = 0;
18541: if(data & 0x40) {
18542: level = data & 7;
18543: } else {
18544: if(!pic[c].isr) {
18545: return;
18546: }
18547: level = pic[c].prio;
18548: while(!(pic[c].isr & (1 << level))) {
18549: level = (level + 1) & 7;
18550: }
18551: }
18552: if(data & 0x80) {
18553: pic[c].prio = (level + 1) & 7;
18554: }
18555: if(data & 0x20) {
18556: pic[c].isr &= ~(1 << level);
18557: }
18558: }
18559: }
18560: pic_update();
18561: }
18562:
18563: UINT8 pic_read(int c, UINT32 addr)
18564: {
18565: if(addr & 1) {
18566: return(pic[c].imr);
18567: } else {
18568: // polling mode is not supported...
18569: //if(pic[c].ocw3 & 4) {
18570: // return ???;
18571: //}
18572: if(pic[c].ocw3 & 1) {
18573: return(pic[c].isr);
18574: } else {
18575: return(pic[c].irr);
18576: }
18577: }
18578: }
18579:
18580: void pic_req(int c, int level, int signal)
18581: {
18582: if(signal) {
18583: pic[c].irr |= (1 << level);
18584: } else {
18585: pic[c].irr &= ~(1 << level);
18586: }
18587: pic_update();
18588: }
18589:
18590: int pic_ack()
18591: {
18592: // ack (INTA=L)
18593: pic[pic_req_chip].isr |= pic_req_bit;
18594: pic[pic_req_chip].irr &= ~pic_req_bit;
18595: if(pic_req_chip > 0) {
18596: // update isr and irr of master
18597: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
18598: pic[pic_req_chip - 1].isr |= slave;
18599: pic[pic_req_chip - 1].irr &= ~slave;
18600: }
18601: //if(pic[pic_req_chip].icw4 & 1) {
18602: // 8086 mode
18603: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
18604: //} else {
18605: // // 8080 mode
18606: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
18607: // if(pic[pic_req_chip].icw1 & 4) {
18608: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
18609: // } else {
18610: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
18611: // }
18612: // vector = 0xcd | (addr << 8);
18613: //}
18614: if(pic[pic_req_chip].icw4 & 2) {
18615: // auto eoi
18616: pic[pic_req_chip].isr &= ~pic_req_bit;
18617: }
18618: return(vector);
18619: }
18620:
18621: void pic_update()
18622: {
18623: for(int c = 0; c < 2; c++) {
18624: UINT8 irr = pic[c].irr;
18625: if(c + 1 < 2) {
18626: // this is master
18627: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
18628: // request from slave
18629: irr |= 1 << (pic[c + 1].icw3 & 7);
18630: }
18631: }
18632: irr &= (~pic[c].imr);
18633: if(!irr) {
18634: break;
18635: }
18636: if(!(pic[c].ocw3 & 0x20)) {
18637: irr |= pic[c].isr;
18638: }
18639: int level = pic[c].prio;
18640: UINT8 bit = 1 << level;
18641: while(!(irr & bit)) {
18642: level = (level + 1) & 7;
18643: bit = 1 << level;
18644: }
18645: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
18646: // check slave
18647: continue;
18648: }
18649: if(pic[c].isr & bit) {
18650: break;
18651: }
18652: // interrupt request
18653: pic_req_chip = c;
18654: pic_req_level = level;
18655: pic_req_bit = bit;
1.1.1.3 root 18656: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 18657: return;
18658: }
1.1.1.3 root 18659: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 18660: }
1.1 root 18661:
1.1.1.25 root 18662: // pio
18663:
18664: void pio_init()
18665: {
1.1.1.38 root 18666: // bool conv_mode = (GetConsoleCP() == 932);
18667:
1.1.1.26 root 18668: memset(pio, 0, sizeof(pio));
1.1.1.37 root 18669:
1.1.1.25 root 18670: for(int c = 0; c < 2; c++) {
1.1.1.37 root 18671: pio[c].stat = 0xdf;
1.1.1.25 root 18672: pio[c].ctrl = 0x0c;
1.1.1.38 root 18673: // pio[c].conv_mode = conv_mode;
1.1.1.25 root 18674: }
18675: }
18676:
1.1.1.37 root 18677: void pio_finish()
18678: {
18679: pio_release();
18680: }
18681:
18682: void pio_release()
18683: {
18684: for(int c = 0; c < 2; c++) {
18685: if(pio[c].fp != NULL) {
1.1.1.38 root 18686: if(pio[c].jis_mode) {
18687: fputc(0x1c, pio[c].fp);
18688: fputc(0x2e, pio[c].fp);
18689: }
1.1.1.37 root 18690: fclose(pio[c].fp);
18691: pio[c].fp = NULL;
18692: }
18693: }
18694: }
18695:
1.1.1.25 root 18696: void pio_write(int c, UINT32 addr, UINT8 data)
18697: {
18698: switch(addr & 3) {
18699: case 0:
18700: pio[c].data = data;
18701: break;
18702: case 2:
1.1.1.37 root 18703: if((pio[c].ctrl & 0x01) && !(data & 0x01)) {
18704: // strobe H -> L
18705: if(pio[c].data == 0x0d && (data & 0x02)) {
18706: // auto feed
18707: printer_out(c, 0x0d);
18708: printer_out(c, 0x0a);
18709: } else {
18710: printer_out(c, pio[c].data);
18711: }
18712: pio[c].stat &= ~0x40; // set ack
18713: }
1.1.1.25 root 18714: pio[c].ctrl = data;
18715: break;
18716: }
18717: }
18718:
18719: UINT8 pio_read(int c, UINT32 addr)
18720: {
18721: switch(addr & 3) {
18722: case 0:
1.1.1.37 root 18723: if(pio[c].ctrl & 0x20) {
18724: // input mode
18725: return(0xff);
18726: }
1.1.1.25 root 18727: return(pio[c].data);
18728: case 1:
1.1.1.37 root 18729: {
18730: UINT8 stat = pio[c].stat;
18731: pio[c].stat |= 0x40; // clear ack
18732: return(stat);
18733: }
1.1.1.25 root 18734: case 2:
18735: return(pio[c].ctrl);
18736: }
18737: return(0xff);
18738: }
18739:
1.1.1.37 root 18740: void printer_out(int c, UINT8 data)
18741: {
18742: SYSTEMTIME time;
1.1.1.38 root 18743: bool jis_mode = false;
1.1.1.37 root 18744:
18745: GetLocalTime(&time);
18746:
18747: if(pio[c].fp != NULL) {
18748: // if at least 1000ms passed from last written, close the current file
18749: FILETIME ftime1;
18750: FILETIME ftime2;
18751: SystemTimeToFileTime(&pio[c].time, &ftime1);
18752: SystemTimeToFileTime(&time, &ftime2);
18753: INT64 *time1 = (INT64 *)&ftime1;
18754: INT64 *time2 = (INT64 *)&ftime2;
18755: INT64 msec = (*time2 - *time1) / 10000;
18756:
18757: if(msec >= 1000) {
1.1.1.38 root 18758: if(pio[c].jis_mode) {
18759: fputc(0x1c, pio[c].fp);
18760: fputc(0x2e, pio[c].fp);
18761: jis_mode = true;
18762: }
1.1.1.37 root 18763: fclose(pio[c].fp);
18764: pio[c].fp = NULL;
18765: }
18766: }
18767: if(pio[c].fp == NULL) {
18768: // create a new file in the temp folder
18769: char file_name[MAX_PATH];
18770:
18771: 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);
18772: if(GetTempPath(MAX_PATH, pio[c].path)) {
18773: strcat(pio[c].path, file_name);
18774: } else {
18775: strcpy(pio[c].path, file_name);
18776: }
1.1.1.38 root 18777: pio[c].fp = fopen(pio[c].path, "w+b");
1.1.1.37 root 18778: }
18779: if(pio[c].fp != NULL) {
1.1.1.38 root 18780: if(jis_mode) {
18781: fputc(0x1c, pio[c].fp);
18782: fputc(0x26, pio[c].fp);
18783: }
1.1.1.37 root 18784: fputc(data, pio[c].fp);
1.1.1.38 root 18785:
18786: // reopen file if 1ch 26h 1ch 2eh (kanji-on kanji-off) are written at the top
18787: if(data == 0x2e && ftell(pio[c].fp) == 4) {
18788: UINT8 buffer[4];
18789: fseek(pio[c].fp, 0, SEEK_SET);
18790: fread(buffer, 4, 1, pio[c].fp);
18791: if(buffer[0] == 0x1c && buffer[1] == 0x26 && buffer[2] == 0x1c/* && buffer[3] == 0x2e*/) {
18792: fclose(pio[c].fp);
18793: pio[c].fp = fopen(pio[c].path, "w+b");
18794: }
18795: }
1.1.1.37 root 18796: pio[c].time = time;
18797: }
18798: }
18799:
1.1 root 18800: // pit
18801:
1.1.1.22 root 18802: #define PIT_FREQ 1193182ULL
1.1 root 18803: #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)
18804:
18805: void pit_init()
18806: {
1.1.1.8 root 18807: memset(pit, 0, sizeof(pit));
1.1 root 18808: for(int ch = 0; ch < 3; ch++) {
18809: pit[ch].count = 0x10000;
18810: pit[ch].ctrl_reg = 0x34;
18811: pit[ch].mode = 3;
18812: }
18813:
18814: // from bochs bios
18815: pit_write(3, 0x34);
18816: pit_write(0, 0x00);
18817: pit_write(0, 0x00);
18818: }
18819:
18820: void pit_write(int ch, UINT8 val)
18821: {
1.1.1.8 root 18822: #ifndef PIT_ALWAYS_RUNNING
1.1 root 18823: if(!pit_active) {
18824: pit_active = 1;
18825: pit_init();
18826: }
1.1.1.8 root 18827: #endif
1.1 root 18828: switch(ch) {
18829: case 0:
18830: case 1:
18831: case 2:
18832: // write count register
18833: if(!pit[ch].low_write && !pit[ch].high_write) {
18834: if(pit[ch].ctrl_reg & 0x10) {
18835: pit[ch].low_write = 1;
18836: }
18837: if(pit[ch].ctrl_reg & 0x20) {
18838: pit[ch].high_write = 1;
18839: }
18840: }
18841: if(pit[ch].low_write) {
18842: pit[ch].count_reg = val;
18843: pit[ch].low_write = 0;
18844: } else if(pit[ch].high_write) {
18845: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
18846: pit[ch].count_reg = val << 8;
18847: } else {
18848: pit[ch].count_reg |= val << 8;
18849: }
18850: pit[ch].high_write = 0;
18851: }
18852: // start count
1.1.1.8 root 18853: if(!pit[ch].low_write && !pit[ch].high_write) {
18854: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
18855: pit[ch].count = PIT_COUNT_VALUE(ch);
18856: pit[ch].prev_time = timeGetTime();
18857: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 18858: }
18859: }
18860: break;
18861: case 3: // ctrl reg
18862: if((val & 0xc0) == 0xc0) {
18863: // i8254 read-back command
18864: for(ch = 0; ch < 3; ch++) {
18865: if(!(val & 0x10) && !pit[ch].status_latched) {
18866: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
18867: pit[ch].status_latched = 1;
18868: }
18869: if(!(val & 0x20) && !pit[ch].count_latched) {
18870: pit_latch_count(ch);
18871: }
18872: }
18873: break;
18874: }
18875: ch = (val >> 6) & 3;
18876: if(val & 0x30) {
1.1.1.35 root 18877: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
1.1 root 18878: pit[ch].mode = modes[(val >> 1) & 7];
18879: pit[ch].count_latched = 0;
18880: pit[ch].low_read = pit[ch].high_read = 0;
18881: pit[ch].low_write = pit[ch].high_write = 0;
18882: pit[ch].ctrl_reg = val;
18883: // stop count
1.1.1.8 root 18884: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 18885: pit[ch].count_reg = 0;
18886: } else if(!pit[ch].count_latched) {
18887: pit_latch_count(ch);
18888: }
18889: break;
18890: }
18891: }
18892:
18893: UINT8 pit_read(int ch)
18894: {
1.1.1.8 root 18895: #ifndef PIT_ALWAYS_RUNNING
1.1 root 18896: if(!pit_active) {
18897: pit_active = 1;
18898: pit_init();
18899: }
1.1.1.8 root 18900: #endif
1.1 root 18901: switch(ch) {
18902: case 0:
18903: case 1:
18904: case 2:
18905: if(pit[ch].status_latched) {
18906: pit[ch].status_latched = 0;
18907: return(pit[ch].status);
18908: }
18909: // if not latched, through current count
18910: if(!pit[ch].count_latched) {
18911: if(!pit[ch].low_read && !pit[ch].high_read) {
18912: pit_latch_count(ch);
18913: }
18914: }
18915: // return latched count
18916: if(pit[ch].low_read) {
18917: pit[ch].low_read = 0;
18918: if(!pit[ch].high_read) {
18919: pit[ch].count_latched = 0;
18920: }
18921: return(pit[ch].latch & 0xff);
18922: } else if(pit[ch].high_read) {
18923: pit[ch].high_read = 0;
18924: pit[ch].count_latched = 0;
18925: return((pit[ch].latch >> 8) & 0xff);
18926: }
18927: }
18928: return(0xff);
18929: }
18930:
1.1.1.8 root 18931: int pit_run(int ch, UINT32 cur_time)
1.1 root 18932: {
1.1.1.8 root 18933: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 18934: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 18935: pit[ch].prev_time = pit[ch].expired_time;
18936: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
18937: if(cur_time >= pit[ch].expired_time) {
18938: pit[ch].prev_time = cur_time;
18939: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 18940: }
1.1.1.8 root 18941: return(1);
1.1 root 18942: }
1.1.1.8 root 18943: return(0);
1.1 root 18944: }
18945:
18946: void pit_latch_count(int ch)
18947: {
1.1.1.8 root 18948: if(pit[ch].expired_time != 0) {
1.1.1.26 root 18949: UINT32 cur_time = timeGetTime();
1.1.1.8 root 18950: pit_run(ch, cur_time);
18951: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 18952: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
18953:
18954: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
18955: // decrement counter in 1msec period
18956: if(pit[ch].next_latch == 0) {
18957: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
18958: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
18959: }
18960: if(pit[ch].latch > pit[ch].next_latch) {
18961: pit[ch].latch--;
18962: }
18963: } else {
18964: pit[ch].prev_latch = pit[ch].latch = latch;
18965: pit[ch].next_latch = 0;
18966: }
1.1.1.8 root 18967: } else {
18968: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 18969: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 18970: }
18971: pit[ch].count_latched = 1;
18972: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
18973: // lower byte
18974: pit[ch].low_read = 1;
18975: pit[ch].high_read = 0;
18976: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
18977: // upper byte
18978: pit[ch].low_read = 0;
18979: pit[ch].high_read = 1;
18980: } else {
18981: // lower -> upper
1.1.1.14 root 18982: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 18983: }
18984: }
18985:
1.1.1.8 root 18986: int pit_get_expired_time(int ch)
1.1 root 18987: {
1.1.1.22 root 18988: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
18989: UINT64 val = pit[ch].accum >> 10;
18990: pit[ch].accum -= val << 10;
18991: return((val != 0) ? val : 1);
1.1.1.8 root 18992: }
18993:
1.1.1.25 root 18994: // sio
18995:
18996: void sio_init()
18997: {
1.1.1.26 root 18998: memset(sio, 0, sizeof(sio));
18999: memset(sio_mt, 0, sizeof(sio_mt));
19000:
1.1.1.29 root 19001: for(int c = 0; c < 4; c++) {
1.1.1.25 root 19002: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
19003: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
19004:
19005: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
19006: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 19007: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
19008: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 19009: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
19010: sio[c].irq_identify = 0x01; // no pending irq
19011:
19012: InitializeCriticalSection(&sio_mt[c].csSendData);
19013: InitializeCriticalSection(&sio_mt[c].csRecvData);
19014: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
19015: InitializeCriticalSection(&sio_mt[c].csLineStat);
19016: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
19017: InitializeCriticalSection(&sio_mt[c].csModemStat);
19018:
1.1.1.26 root 19019: if(sio_port_number[c] != 0) {
1.1.1.25 root 19020: sio[c].channel = c;
19021: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
19022: }
19023: }
19024: }
19025:
19026: void sio_finish()
19027: {
1.1.1.29 root 19028: for(int c = 0; c < 4; c++) {
1.1.1.25 root 19029: if(sio_mt[c].hThread != NULL) {
19030: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
19031: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 19032: sio_mt[c].hThread = NULL;
1.1.1.25 root 19033: }
19034: DeleteCriticalSection(&sio_mt[c].csSendData);
19035: DeleteCriticalSection(&sio_mt[c].csRecvData);
19036: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
19037: DeleteCriticalSection(&sio_mt[c].csLineStat);
19038: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
19039: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 19040: }
19041: sio_release();
19042: }
19043:
19044: void sio_release()
19045: {
1.1.1.29 root 19046: for(int c = 0; c < 4; c++) {
1.1.1.28 root 19047: // sio_thread() may access the resources :-(
1.1.1.32 root 19048: bool running = (sio_mt[c].hThread != NULL);
19049:
19050: if(running) {
19051: EnterCriticalSection(&sio_mt[c].csSendData);
19052: }
19053: if(sio[c].send_buffer != NULL) {
19054: sio[c].send_buffer->release();
19055: delete sio[c].send_buffer;
19056: sio[c].send_buffer = NULL;
19057: }
19058: if(running) {
19059: LeaveCriticalSection(&sio_mt[c].csSendData);
19060: EnterCriticalSection(&sio_mt[c].csRecvData);
19061: }
19062: if(sio[c].recv_buffer != NULL) {
19063: sio[c].recv_buffer->release();
19064: delete sio[c].recv_buffer;
19065: sio[c].recv_buffer = NULL;
19066: }
19067: if(running) {
19068: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 19069: }
1.1.1.25 root 19070: }
19071: }
19072:
19073: void sio_write(int c, UINT32 addr, UINT8 data)
19074: {
19075: switch(addr & 7) {
19076: case 0:
19077: if(sio[c].selector & 0x80) {
19078: if(sio[c].divisor.b.l != data) {
19079: EnterCriticalSection(&sio_mt[c].csLineCtrl);
19080: sio[c].divisor.b.l = data;
19081: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
19082: }
19083: } else {
19084: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 19085: if(sio[c].send_buffer != NULL) {
19086: sio[c].send_buffer->write(data);
19087: }
1.1.1.25 root 19088: // transmitter holding/shift registers are not empty
19089: sio[c].line_stat_buf &= ~0x60;
19090: LeaveCriticalSection(&sio_mt[c].csSendData);
19091:
19092: if(sio[c].irq_enable & 0x02) {
19093: sio_update_irq(c);
19094: }
19095: }
19096: break;
19097: case 1:
19098: if(sio[c].selector & 0x80) {
19099: if(sio[c].divisor.b.h != data) {
19100: EnterCriticalSection(&sio_mt[c].csLineCtrl);
19101: sio[c].divisor.b.h = data;
19102: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
19103: }
19104: } else {
19105: if(sio[c].irq_enable != data) {
19106: sio[c].irq_enable = data;
19107: sio_update_irq(c);
19108: }
19109: }
19110: break;
19111: case 3:
19112: {
19113: UINT8 line_ctrl = data & 0x3f;
19114: bool set_brk = ((data & 0x40) != 0);
19115:
19116: if(sio[c].line_ctrl != line_ctrl) {
19117: EnterCriticalSection(&sio_mt[c].csLineCtrl);
19118: sio[c].line_ctrl = line_ctrl;
19119: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
19120: }
19121: if(sio[c].set_brk != set_brk) {
19122: EnterCriticalSection(&sio_mt[c].csModemCtrl);
19123: sio[c].set_brk = set_brk;
19124: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
19125: }
19126: }
19127: sio[c].selector = data;
19128: break;
19129: case 4:
19130: {
19131: bool set_dtr = ((data & 0x01) != 0);
19132: bool set_rts = ((data & 0x02) != 0);
19133:
19134: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 19135: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 19136: sio[c].set_dtr = set_dtr;
19137: sio[c].set_rts = set_rts;
1.1.1.26 root 19138: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
19139:
19140: bool state_changed = false;
19141:
19142: EnterCriticalSection(&sio_mt[c].csModemStat);
19143: if(set_dtr) {
19144: sio[c].modem_stat |= 0x20; // dsr on
19145: } else {
19146: sio[c].modem_stat &= ~0x20; // dsr off
19147: }
19148: if(set_rts) {
19149: sio[c].modem_stat |= 0x10; // cts on
19150: } else {
19151: sio[c].modem_stat &= ~0x10; // cts off
19152: }
19153: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
19154: if(!(sio[c].modem_stat & 0x02)) {
19155: if(sio[c].irq_enable & 0x08) {
19156: state_changed = true;
19157: }
19158: sio[c].modem_stat |= 0x02;
19159: }
19160: }
19161: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
19162: if(!(sio[c].modem_stat & 0x01)) {
19163: if(sio[c].irq_enable & 0x08) {
19164: state_changed = true;
19165: }
19166: sio[c].modem_stat |= 0x01;
19167: }
19168: }
19169: LeaveCriticalSection(&sio_mt[c].csModemStat);
19170:
19171: if(state_changed) {
19172: sio_update_irq(c);
19173: }
1.1.1.25 root 19174: }
19175: }
19176: sio[c].modem_ctrl = data;
19177: break;
19178: case 7:
19179: sio[c].scratch = data;
19180: break;
19181: }
19182: }
19183:
19184: UINT8 sio_read(int c, UINT32 addr)
19185: {
19186: switch(addr & 7) {
19187: case 0:
19188: if(sio[c].selector & 0x80) {
19189: return(sio[c].divisor.b.l);
19190: } else {
19191: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 19192: UINT8 data = 0;
19193: if(sio[c].recv_buffer != NULL) {
19194: data = sio[c].recv_buffer->read();
19195: }
1.1.1.25 root 19196: // data is not ready
19197: sio[c].line_stat_buf &= ~0x01;
19198: LeaveCriticalSection(&sio_mt[c].csRecvData);
19199:
19200: if(sio[c].irq_enable & 0x01) {
19201: sio_update_irq(c);
19202: }
19203: return(data);
19204: }
19205: case 1:
19206: if(sio[c].selector & 0x80) {
19207: return(sio[c].divisor.b.h);
19208: } else {
19209: return(sio[c].irq_enable);
19210: }
19211: case 2:
19212: return(sio[c].irq_identify);
19213: case 3:
19214: return(sio[c].selector);
19215: case 4:
19216: return(sio[c].modem_ctrl);
19217: case 5:
19218: {
19219: EnterCriticalSection(&sio_mt[c].csLineStat);
19220: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
19221: sio[c].line_stat_err = 0x00;
19222: LeaveCriticalSection(&sio_mt[c].csLineStat);
19223:
19224: bool state_changed = false;
19225:
19226: if((sio[c].line_stat_buf & 0x60) == 0x00) {
19227: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 19228: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 19229: // transmitter holding register will be empty first
19230: if(sio[c].irq_enable & 0x02) {
19231: state_changed = true;
19232: }
19233: sio[c].line_stat_buf |= 0x20;
19234: }
19235: LeaveCriticalSection(&sio_mt[c].csSendData);
19236: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
19237: // transmitter shift register will be empty later
19238: sio[c].line_stat_buf |= 0x40;
19239: }
19240: if(!(sio[c].line_stat_buf & 0x01)) {
19241: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 19242: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 19243: // data is ready
19244: if(sio[c].irq_enable & 0x01) {
19245: state_changed = true;
19246: }
19247: sio[c].line_stat_buf |= 0x01;
19248: }
19249: LeaveCriticalSection(&sio_mt[c].csRecvData);
19250: }
19251: if(state_changed) {
19252: sio_update_irq(c);
19253: }
19254: return(val);
19255: }
19256: case 6:
19257: {
19258: EnterCriticalSection(&sio_mt[c].csModemStat);
19259: UINT8 val = sio[c].modem_stat;
19260: sio[c].modem_stat &= 0xf0;
19261: sio[c].prev_modem_stat = sio[c].modem_stat;
19262: LeaveCriticalSection(&sio_mt[c].csModemStat);
19263:
19264: if(sio[c].modem_ctrl & 0x10) {
19265: // loop-back
19266: val &= 0x0f;
19267: val |= (sio[c].modem_ctrl & 0x0c) << 4;
19268: val |= (sio[c].modem_ctrl & 0x01) << 5;
19269: val |= (sio[c].modem_ctrl & 0x02) << 3;
19270: }
19271: return(val);
19272: }
19273: case 7:
19274: return(sio[c].scratch);
19275: }
19276: return(0xff);
19277: }
19278:
19279: void sio_update(int c)
19280: {
19281: if((sio[c].line_stat_buf & 0x60) == 0x00) {
19282: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 19283: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 19284: // transmitter holding/shift registers will be empty
19285: sio[c].line_stat_buf |= 0x60;
19286: }
19287: LeaveCriticalSection(&sio_mt[c].csSendData);
19288: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
19289: // transmitter shift register will be empty
19290: sio[c].line_stat_buf |= 0x40;
19291: }
19292: if(!(sio[c].line_stat_buf & 0x01)) {
19293: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 19294: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 19295: // data is ready
19296: sio[c].line_stat_buf |= 0x01;
19297: }
19298: LeaveCriticalSection(&sio_mt[c].csRecvData);
19299: }
19300: sio_update_irq(c);
19301: }
19302:
19303: void sio_update_irq(int c)
19304: {
19305: int level = -1;
19306:
19307: if(sio[c].irq_enable & 0x08) {
19308: EnterCriticalSection(&sio_mt[c].csModemStat);
19309: if((sio[c].modem_stat & 0x0f) != 0) {
19310: level = 0;
19311: }
19312: EnterCriticalSection(&sio_mt[c].csModemStat);
19313: }
19314: if(sio[c].irq_enable & 0x02) {
19315: if(sio[c].line_stat_buf & 0x20) {
19316: level = 1;
19317: }
19318: }
19319: if(sio[c].irq_enable & 0x01) {
19320: if(sio[c].line_stat_buf & 0x01) {
19321: level = 2;
19322: }
19323: }
19324: if(sio[c].irq_enable & 0x04) {
19325: EnterCriticalSection(&sio_mt[c].csLineStat);
19326: if(sio[c].line_stat_err != 0) {
19327: level = 3;
19328: }
19329: LeaveCriticalSection(&sio_mt[c].csLineStat);
19330: }
1.1.1.29 root 19331:
19332: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 19333: if(level != -1) {
19334: sio[c].irq_identify = level << 1;
1.1.1.29 root 19335: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 19336: } else {
19337: sio[c].irq_identify = 1;
1.1.1.29 root 19338: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 19339: }
19340: }
19341:
19342: DWORD WINAPI sio_thread(void *lpx)
19343: {
19344: volatile sio_t *p = (sio_t *)lpx;
19345: sio_mt_t *q = &sio_mt[p->channel];
19346:
19347: char name[] = "COM1";
1.1.1.26 root 19348: name[3] = '0' + sio_port_number[p->channel];
19349: HANDLE hComm = NULL;
19350: COMMPROP commProp;
19351: DCB dcb;
19352: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
19353: BYTE bytBuffer[SIO_BUFFER_SIZE];
19354:
19355: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
19356: if(GetCommProperties(hComm, &commProp)) {
19357: dwSettableBaud = commProp.dwSettableBaud;
19358: }
1.1.1.25 root 19359: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 19360: // EscapeCommFunction(hComm, SETRTS);
19361: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 19362:
19363: while(!m_halted) {
19364: // setup comm port
19365: bool comm_state_changed = false;
19366:
19367: EnterCriticalSection(&q->csLineCtrl);
19368: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
19369: p->prev_divisor = p->divisor.w;
19370: p->prev_line_ctrl = p->line_ctrl;
19371: comm_state_changed = true;
19372: }
19373: LeaveCriticalSection(&q->csLineCtrl);
19374:
19375: if(comm_state_changed) {
1.1.1.26 root 19376: if(GetCommState(hComm, &dcb)) {
19377: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
19378: DWORD baud = 115200 / p->prev_divisor;
19379: dcb.BaudRate = 9600; // default
19380:
19381: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
19382: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
19383: // 134.5bps is not supported ???
19384: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
19385: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
19386: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
19387: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
19388: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
19389: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
19390: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
19391: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
19392: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
19393: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
19394: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
19395: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
19396: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
19397:
19398: switch(p->prev_line_ctrl & 0x03) {
19399: case 0x00: dcb.ByteSize = 5; break;
19400: case 0x01: dcb.ByteSize = 6; break;
19401: case 0x02: dcb.ByteSize = 7; break;
19402: case 0x03: dcb.ByteSize = 8; break;
19403: }
19404: switch(p->prev_line_ctrl & 0x04) {
19405: case 0x00: dcb.StopBits = ONESTOPBIT; break;
19406: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
19407: }
19408: switch(p->prev_line_ctrl & 0x38) {
19409: case 0x08: dcb.Parity = ODDPARITY; break;
19410: case 0x18: dcb.Parity = EVENPARITY; break;
19411: case 0x28: dcb.Parity = MARKPARITY; break;
19412: case 0x38: dcb.Parity = SPACEPARITY; break;
19413: default: dcb.Parity = NOPARITY; break;
19414: }
19415: dcb.fBinary = TRUE;
19416: dcb.fParity = (dcb.Parity != NOPARITY);
19417: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
19418: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
19419: dcb.fDsrSensitivity = FALSE;//TRUE;
19420: dcb.fTXContinueOnXoff = TRUE;
19421: dcb.fOutX = dcb.fInX = FALSE;
19422: dcb.fErrorChar = FALSE;
19423: dcb.fNull = FALSE;
19424: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
19425: dcb.fAbortOnError = FALSE;
19426:
19427: SetCommState(hComm, &dcb);
1.1.1.25 root 19428: }
19429:
19430: // check again to apply all comm state changes
19431: Sleep(10);
19432: continue;
19433: }
19434:
19435: // set comm pins
19436: bool change_brk = false;
1.1.1.26 root 19437: // bool change_rts = false;
19438: // bool change_dtr = false;
1.1.1.25 root 19439:
19440: EnterCriticalSection(&q->csModemCtrl);
19441: if(p->prev_set_brk != p->set_brk) {
19442: p->prev_set_brk = p->set_brk;
19443: change_brk = true;
19444: }
1.1.1.26 root 19445: // if(p->prev_set_rts != p->set_rts) {
19446: // p->prev_set_rts = p->set_rts;
19447: // change_rts = true;
19448: // }
19449: // if(p->prev_set_dtr != p->set_dtr) {
19450: // p->prev_set_dtr = p->set_dtr;
19451: // change_dtr = true;
19452: // }
1.1.1.25 root 19453: LeaveCriticalSection(&q->csModemCtrl);
19454:
19455: if(change_brk) {
1.1.1.26 root 19456: static UINT32 clear_time = 0;
19457: if(p->prev_set_brk) {
19458: EscapeCommFunction(hComm, SETBREAK);
19459: clear_time = timeGetTime() + 200;
19460: } else {
19461: // keep break for at least 200msec
19462: UINT32 cur_time = timeGetTime();
19463: if(clear_time > cur_time) {
19464: Sleep(clear_time - cur_time);
19465: }
19466: EscapeCommFunction(hComm, CLRBREAK);
19467: }
1.1.1.25 root 19468: }
1.1.1.26 root 19469: // if(change_rts) {
19470: // if(p->prev_set_rts) {
19471: // EscapeCommFunction(hComm, SETRTS);
19472: // } else {
19473: // EscapeCommFunction(hComm, CLRRTS);
19474: // }
19475: // }
19476: // if(change_dtr) {
19477: // if(p->prev_set_dtr) {
19478: // EscapeCommFunction(hComm, SETDTR);
19479: // } else {
19480: // EscapeCommFunction(hComm, CLRDTR);
19481: // }
19482: // }
1.1.1.25 root 19483:
19484: // get comm pins
19485: DWORD dwModemStat = 0;
19486:
19487: if(GetCommModemStatus(hComm, &dwModemStat)) {
19488: EnterCriticalSection(&q->csModemStat);
19489: if(dwModemStat & MS_RLSD_ON) {
19490: p->modem_stat |= 0x80;
19491: } else {
19492: p->modem_stat &= ~0x80;
19493: }
19494: if(dwModemStat & MS_RING_ON) {
19495: p->modem_stat |= 0x40;
19496: } else {
19497: p->modem_stat &= ~0x40;
19498: }
1.1.1.26 root 19499: // if(dwModemStat & MS_DSR_ON) {
19500: // p->modem_stat |= 0x20;
19501: // } else {
19502: // p->modem_stat &= ~0x20;
19503: // }
19504: // if(dwModemStat & MS_CTS_ON) {
19505: // p->modem_stat |= 0x10;
19506: // } else {
19507: // p->modem_stat &= ~0x10;
19508: // }
1.1.1.25 root 19509: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
19510: p->modem_stat |= 0x08;
19511: }
19512: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
19513: p->modem_stat |= 0x04;
19514: }
1.1.1.26 root 19515: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
19516: // p->modem_stat |= 0x02;
19517: // }
19518: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
19519: // p->modem_stat |= 0x01;
19520: // }
1.1.1.25 root 19521: LeaveCriticalSection(&q->csModemStat);
19522: }
19523:
19524: // send data
19525: DWORD dwSend = 0;
19526:
19527: EnterCriticalSection(&q->csSendData);
1.1.1.32 root 19528: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 19529: bytBuffer[dwSend++] = p->send_buffer->read();
19530: }
19531: LeaveCriticalSection(&q->csSendData);
19532:
19533: if(dwSend != 0) {
19534: DWORD dwWritten = 0;
19535: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
19536: }
19537:
19538: // get line status and recv data
19539: DWORD dwLineStat = 0;
19540: COMSTAT comStat;
19541:
19542: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
19543: EnterCriticalSection(&q->csLineStat);
19544: if(dwLineStat & CE_BREAK) {
19545: p->line_stat_err |= 0x10;
19546: }
19547: if(dwLineStat & CE_FRAME) {
19548: p->line_stat_err |= 0x08;
19549: }
19550: if(dwLineStat & CE_RXPARITY) {
19551: p->line_stat_err |= 0x04;
19552: }
19553: if(dwLineStat & CE_OVERRUN) {
19554: p->line_stat_err |= 0x02;
19555: }
19556: LeaveCriticalSection(&q->csLineStat);
19557:
19558: if(comStat.cbInQue != 0) {
19559: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 19560: DWORD dwRecv = 0;
19561: if(p->recv_buffer != NULL) {
19562: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
19563: }
1.1.1.25 root 19564: LeaveCriticalSection(&q->csRecvData);
19565:
19566: if(dwRecv != 0) {
19567: DWORD dwRead = 0;
19568: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
19569: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 19570: if(p->recv_buffer != NULL) {
19571: for(int i = 0; i < dwRead; i++) {
19572: p->recv_buffer->write(bytBuffer[i]);
19573: }
1.1.1.25 root 19574: }
19575: LeaveCriticalSection(&q->csRecvData);
19576: }
19577: }
19578: }
19579: }
19580: Sleep(10);
19581: }
19582: CloseHandle(hComm);
19583: }
19584: return 0;
19585: }
19586:
1.1.1.8 root 19587: // cmos
19588:
19589: void cmos_init()
19590: {
19591: memset(cmos, 0, sizeof(cmos));
19592: cmos_addr = 0;
1.1 root 19593:
1.1.1.8 root 19594: // from DOSBox
19595: cmos_write(0x0a, 0x26);
19596: cmos_write(0x0b, 0x02);
19597: cmos_write(0x0d, 0x80);
1.1 root 19598: }
19599:
1.1.1.8 root 19600: void cmos_write(int addr, UINT8 val)
1.1 root 19601: {
1.1.1.8 root 19602: cmos[addr & 0x7f] = val;
19603: }
19604:
19605: #define CMOS_GET_TIME() { \
19606: UINT32 cur_sec = timeGetTime() / 1000 ; \
19607: if(prev_sec != cur_sec) { \
19608: GetLocalTime(&time); \
19609: prev_sec = cur_sec; \
19610: } \
1.1 root 19611: }
1.1.1.8 root 19612: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 19613:
1.1.1.8 root 19614: UINT8 cmos_read(int addr)
1.1 root 19615: {
1.1.1.8 root 19616: static SYSTEMTIME time;
19617: static UINT32 prev_sec = 0;
1.1 root 19618:
1.1.1.8 root 19619: switch(addr & 0x7f) {
19620: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
19621: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
19622: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
19623: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
19624: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
19625: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
19626: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
19627: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
19628: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
19629: case 0x15: return((MEMORY_END >> 10) & 0xff);
19630: case 0x16: return((MEMORY_END >> 18) & 0xff);
19631: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
19632: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
19633: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
19634: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
19635: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 19636: }
1.1.1.8 root 19637: return(cmos[addr & 0x7f]);
1.1 root 19638: }
19639:
1.1.1.7 root 19640: // kbd (a20)
19641:
19642: void kbd_init()
19643: {
1.1.1.8 root 19644: kbd_data = kbd_command = 0;
1.1.1.7 root 19645: kbd_status = 0x18;
19646: }
19647:
19648: UINT8 kbd_read_data()
19649: {
1.1.1.8 root 19650: kbd_status &= ~1;
1.1.1.7 root 19651: return(kbd_data);
19652: }
19653:
19654: void kbd_write_data(UINT8 val)
19655: {
19656: switch(kbd_command) {
19657: case 0xd1:
19658: i386_set_a20_line((val >> 1) & 1);
19659: break;
19660: }
19661: kbd_command = 0;
1.1.1.8 root 19662: kbd_status &= ~8;
1.1.1.7 root 19663: }
19664:
19665: UINT8 kbd_read_status()
19666: {
19667: return(kbd_status);
19668: }
19669:
19670: void kbd_write_command(UINT8 val)
19671: {
19672: switch(val) {
19673: case 0xd0:
19674: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 19675: kbd_status |= 1;
1.1.1.7 root 19676: break;
19677: case 0xdd:
19678: i386_set_a20_line(0);
19679: break;
19680: case 0xdf:
19681: i386_set_a20_line(1);
19682: break;
1.1.1.26 root 19683: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
19684: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 19685: if(!(val & 1)) {
1.1.1.8 root 19686: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 19687: // reset pic
19688: pic_init();
19689: pic[0].irr = pic[1].irr = 0x00;
19690: pic[0].imr = pic[1].imr = 0xff;
19691: }
19692: CPU_RESET_CALL(CPU_MODEL);
1.1.1.40 root 19693: UINT16 address = *(UINT16 *)(mem + 0x467);
19694: UINT16 selector = *(UINT16 *)(mem + 0x469);
19695: i386_jmp_far(selector, address);
1.1.1.7 root 19696: }
19697: i386_set_a20_line((val >> 1) & 1);
19698: break;
19699: }
19700: kbd_command = val;
1.1.1.8 root 19701: kbd_status |= 8;
1.1.1.7 root 19702: }
19703:
1.1.1.9 root 19704: // vga
19705:
19706: UINT8 vga_read_status()
19707: {
19708: // 60hz
19709: static const int period[3] = {16, 17, 17};
19710: static int index = 0;
19711: UINT32 time = timeGetTime() % period[index];
19712:
19713: index = (index + 1) % 3;
1.1.1.14 root 19714: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 19715: }
19716:
1.1 root 19717: // i/o bus
19718:
1.1.1.29 root 19719: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
19720: //#define SW1US_PATCH
19721:
1.1.1.25 root 19722: UINT8 read_io_byte(offs_t addr)
1.1.1.33 root 19723: #ifdef USE_DEBUGGER
1.1.1.25 root 19724: {
1.1.1.33 root 19725: if(now_debugging) {
19726: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
19727: if(in_break_point.table[i].status == 1) {
19728: if(addr == in_break_point.table[i].addr) {
19729: in_break_point.hit = i + 1;
19730: now_suspended = true;
19731: break;
19732: }
19733: }
19734: }
1.1.1.25 root 19735: }
1.1.1.33 root 19736: return(debugger_read_io_byte(addr));
1.1.1.25 root 19737: }
1.1.1.33 root 19738: UINT8 debugger_read_io_byte(offs_t addr)
1.1.1.25 root 19739: #endif
1.1 root 19740: {
1.1.1.33 root 19741: UINT8 val = 0xff;
19742:
1.1 root 19743: switch(addr) {
1.1.1.29 root 19744: #ifdef SW1US_PATCH
19745: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
19746: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
1.1.1.33 root 19747: val = sio_read(0, addr - 1);
19748: break;
1.1.1.29 root 19749: #else
1.1.1.25 root 19750: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
19751: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1.1.1.33 root 19752: val = dma_read(0, addr);
19753: break;
1.1.1.29 root 19754: #endif
1.1.1.25 root 19755: case 0x20: case 0x21:
1.1.1.33 root 19756: val = pic_read(0, addr);
19757: break;
1.1.1.25 root 19758: case 0x40: case 0x41: case 0x42: case 0x43:
1.1.1.33 root 19759: val = pit_read(addr & 0x03);
19760: break;
1.1.1.7 root 19761: case 0x60:
1.1.1.33 root 19762: val = kbd_read_data();
19763: break;
1.1.1.9 root 19764: case 0x61:
1.1.1.33 root 19765: val = system_port;
19766: break;
1.1.1.7 root 19767: case 0x64:
1.1.1.33 root 19768: val = kbd_read_status();
19769: break;
1.1 root 19770: case 0x71:
1.1.1.33 root 19771: val = cmos_read(cmos_addr);
19772: break;
1.1.1.25 root 19773: case 0x81:
1.1.1.33 root 19774: val = dma_page_read(0, 2);
19775: break;
1.1.1.25 root 19776: case 0x82:
1.1.1.33 root 19777: val = dma_page_read(0, 3);
19778: break;
1.1.1.25 root 19779: case 0x83:
1.1.1.33 root 19780: val = dma_page_read(0, 1);
19781: break;
1.1.1.25 root 19782: case 0x87:
1.1.1.33 root 19783: val = dma_page_read(0, 0);
19784: break;
1.1.1.25 root 19785: case 0x89:
1.1.1.33 root 19786: val = dma_page_read(1, 2);
19787: break;
1.1.1.25 root 19788: case 0x8a:
1.1.1.33 root 19789: val = dma_page_read(1, 3);
19790: break;
1.1.1.25 root 19791: case 0x8b:
1.1.1.33 root 19792: val = dma_page_read(1, 1);
19793: break;
1.1.1.25 root 19794: case 0x8f:
1.1.1.33 root 19795: val = dma_page_read(1, 0);
19796: break;
1.1 root 19797: case 0x92:
1.1.1.33 root 19798: val = (m_a20_mask >> 19) & 2;
19799: break;
1.1.1.25 root 19800: case 0xa0: case 0xa1:
1.1.1.33 root 19801: val = pic_read(1, addr);
19802: break;
1.1.1.25 root 19803: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
19804: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.33 root 19805: val = dma_read(1, (addr - 0xc0) >> 1);
19806: break;
1.1.1.37 root 19807: case 0x278: case 0x279: case 0x27a:
19808: val = pio_read(1, addr);
19809: break;
1.1.1.29 root 19810: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
1.1.1.33 root 19811: val = sio_read(3, addr);
19812: break;
1.1.1.25 root 19813: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
1.1.1.33 root 19814: val = sio_read(1, addr);
19815: break;
1.1.1.25 root 19816: case 0x378: case 0x379: case 0x37a:
1.1.1.33 root 19817: val = pio_read(0, addr);
19818: break;
1.1.1.25 root 19819: case 0x3ba: case 0x3da:
1.1.1.33 root 19820: val = vga_read_status();
19821: break;
1.1.1.37 root 19822: case 0x3bc: case 0x3bd: case 0x3be:
19823: val = pio_read(2, addr);
19824: break;
1.1.1.29 root 19825: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
1.1.1.33 root 19826: val = sio_read(2, addr);
19827: break;
1.1.1.25 root 19828: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
1.1.1.33 root 19829: val = sio_read(0, addr);
19830: break;
1.1 root 19831: default:
1.1.1.33 root 19832: // fatalerror("unknown inb %4x\n", addr);
1.1 root 19833: break;
19834: }
1.1.1.33 root 19835: #ifdef ENABLE_DEBUG_IOPORT
19836: if(fp_debug_log != NULL) {
19837: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
19838: }
19839: #endif
19840: return(val);
1.1 root 19841: }
19842:
19843: UINT16 read_io_word(offs_t addr)
19844: {
19845: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
19846: }
19847:
1.1.1.33 root 19848: #ifdef USE_DEBUGGER
19849: UINT16 debugger_read_io_word(offs_t addr)
19850: {
19851: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
19852: }
19853: #endif
19854:
1.1 root 19855: UINT32 read_io_dword(offs_t addr)
19856: {
19857: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
19858: }
19859:
1.1.1.33 root 19860: #ifdef USE_DEBUGGER
19861: UINT32 debugger_read_io_dword(offs_t addr)
19862: {
19863: 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));
19864: }
19865: #endif
19866:
1.1 root 19867: void write_io_byte(offs_t addr, UINT8 val)
1.1.1.33 root 19868: #ifdef USE_DEBUGGER
19869: {
19870: if(now_debugging) {
19871: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
19872: if(out_break_point.table[i].status == 1) {
19873: if(addr == out_break_point.table[i].addr) {
19874: out_break_point.hit = i + 1;
19875: now_suspended = true;
19876: break;
19877: }
19878: }
19879: }
19880: }
19881: debugger_write_io_byte(addr, val);
19882: }
19883: void debugger_write_io_byte(offs_t addr, UINT8 val)
19884: #endif
1.1 root 19885: {
1.1.1.25 root 19886: #ifdef ENABLE_DEBUG_IOPORT
1.1.1.33 root 19887: if(fp_debug_log != NULL) {
1.1.1.43 root 19888: #ifdef USE_SERVICE_THREAD
19889: if(addr != 0xf7)
19890: #endif
1.1.1.33 root 19891: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
1.1.1.25 root 19892: }
19893: #endif
1.1 root 19894: switch(addr) {
1.1.1.29 root 19895: #ifdef SW1US_PATCH
19896: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
19897: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
19898: sio_write(0, addr - 1, val);
19899: break;
19900: #else
1.1.1.25 root 19901: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
19902: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
19903: dma_write(0, addr, val);
19904: break;
1.1.1.29 root 19905: #endif
1.1.1.25 root 19906: case 0x20: case 0x21:
1.1 root 19907: pic_write(0, addr, val);
19908: break;
1.1.1.25 root 19909: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 19910: pit_write(addr & 0x03, val);
19911: break;
1.1.1.7 root 19912: case 0x60:
19913: kbd_write_data(val);
19914: break;
1.1.1.9 root 19915: case 0x61:
19916: if((system_port & 3) != 3 && (val & 3) == 3) {
19917: // beep on
19918: // MessageBeep(-1);
19919: } else if((system_port & 3) == 3 && (val & 3) != 3) {
19920: // beep off
19921: }
19922: system_port = val;
19923: break;
1.1 root 19924: case 0x64:
1.1.1.7 root 19925: kbd_write_command(val);
1.1 root 19926: break;
19927: case 0x70:
19928: cmos_addr = val;
19929: break;
19930: case 0x71:
1.1.1.8 root 19931: cmos_write(cmos_addr, val);
1.1 root 19932: break;
1.1.1.25 root 19933: case 0x81:
19934: dma_page_write(0, 2, val);
19935: case 0x82:
19936: dma_page_write(0, 3, val);
19937: case 0x83:
19938: dma_page_write(0, 1, val);
19939: case 0x87:
19940: dma_page_write(0, 0, val);
19941: case 0x89:
19942: dma_page_write(1, 2, val);
19943: case 0x8a:
19944: dma_page_write(1, 3, val);
19945: case 0x8b:
19946: dma_page_write(1, 1, val);
19947: case 0x8f:
19948: dma_page_write(1, 0, val);
1.1 root 19949: case 0x92:
1.1.1.7 root 19950: i386_set_a20_line((val >> 1) & 1);
1.1 root 19951: break;
1.1.1.25 root 19952: case 0xa0: case 0xa1:
1.1 root 19953: pic_write(1, addr, val);
19954: break;
1.1.1.25 root 19955: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
19956: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 19957: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 19958: break;
1.1.1.35 root 19959: #ifdef USE_SERVICE_THREAD
19960: case 0xf7:
19961: // dummy i/o for BIOS/DOS service
1.1.1.36 root 19962: if(in_service && cursor_moved) {
19963: // update cursor position before service is done
19964: pcbios_update_cursor_position();
19965: cursor_moved = false;
19966: }
1.1.1.35 root 19967: finish_service_loop();
19968: break;
19969: #endif
1.1.1.37 root 19970: case 0x278: case 0x279: case 0x27a:
19971: pio_write(1, addr, val);
19972: break;
1.1.1.29 root 19973: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
19974: sio_write(3, addr, val);
19975: break;
1.1.1.25 root 19976: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
19977: sio_write(1, addr, val);
19978: break;
19979: case 0x378: case 0x379: case 0x37a:
19980: pio_write(0, addr, val);
19981: break;
1.1.1.37 root 19982: case 0x3bc: case 0x3bd: case 0x3be:
19983: pio_write(2, addr, val);
19984: break;
1.1.1.29 root 19985: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
19986: sio_write(2, addr, val);
19987: break;
1.1.1.25 root 19988: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
19989: sio_write(0, addr, val);
19990: break;
1.1 root 19991: default:
1.1.1.33 root 19992: // fatalerror("unknown outb %4x,%2x\n", addr, val);
1.1 root 19993: break;
19994: }
19995: }
19996:
19997: void write_io_word(offs_t addr, UINT16 val)
19998: {
19999: write_io_byte(addr + 0, (val >> 0) & 0xff);
20000: write_io_byte(addr + 1, (val >> 8) & 0xff);
20001: }
20002:
1.1.1.33 root 20003: #ifdef USE_DEBUGGER
20004: void debugger_write_io_word(offs_t addr, UINT16 val)
20005: {
20006: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
20007: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
20008: }
20009: #endif
20010:
1.1 root 20011: void write_io_dword(offs_t addr, UINT32 val)
20012: {
20013: write_io_byte(addr + 0, (val >> 0) & 0xff);
20014: write_io_byte(addr + 1, (val >> 8) & 0xff);
20015: write_io_byte(addr + 2, (val >> 16) & 0xff);
20016: write_io_byte(addr + 3, (val >> 24) & 0xff);
20017: }
1.1.1.33 root 20018:
20019: #ifdef USE_DEBUGGER
20020: void debugger_write_io_dword(offs_t addr, UINT32 val)
20021: {
20022: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
20023: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
20024: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
20025: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
20026: }
20027: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.