|
|
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.25 root 34: #define unimplemented_14h fatalerror
1.1.1.22 root 35: #define unimplemented_15h fatalerror
36: #define unimplemented_16h fatalerror
37: #define unimplemented_1ah fatalerror
38: #define unimplemented_21h fatalerror
39: #define unimplemented_2fh fatalerror
1.1.1.24 root 40: #define unimplemented_33h fatalerror
1.1.1.22 root 41: #define unimplemented_67h fatalerror
42: #define unimplemented_xms fatalerror
43: #endif
44: #endif
45: #ifndef unimplemented_10h
46: #define unimplemented_10h nolog
47: #endif
1.1.1.25 root 48: #ifndef unimplemented_14h
49: #define unimplemented_14h nolog
50: #endif
1.1.1.22 root 51: #ifndef unimplemented_15h
52: #define unimplemented_15h nolog
53: #endif
54: #ifndef unimplemented_16h
55: #define unimplemented_16h nolog
56: #endif
57: #ifndef unimplemented_1ah
58: #define unimplemented_1ah nolog
59: #endif
60: #ifndef unimplemented_21h
61: #define unimplemented_21h nolog
62: #endif
63: #ifndef unimplemented_2fh
64: #define unimplemented_2fh nolog
65: #endif
1.1.1.24 root 66: #ifndef unimplemented_33h
67: #define unimplemented_33h nolog
68: #endif
1.1.1.22 root 69: #ifndef unimplemented_67h
70: #define unimplemented_67h nolog
71: #endif
72: #ifndef unimplemented_xms
73: #define unimplemented_xms nolog
74: #endif
75:
1.1.1.32 root 76: #define array_length(array) (sizeof(array) / sizeof(array[0]))
1.1.1.22 root 77: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
78: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
79: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 80:
1.1.1.12 root 81: #if defined(__MINGW32__)
82: extern "C" int _CRT_glob = 0;
83: #endif
84:
85: /*
86: kludge for "more-standardized" C++
87: */
88: #if !defined(_MSC_VER)
89: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
90: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
91: #define min(a,b) kludge_min(a,b)
92: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 93: #elif _MSC_VER >= 1400
94: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
95: {
96: }
97: #endif
98:
1.1.1.35! root 99: #define USE_VRAM_THREAD
1.1.1.14 root 100:
1.1.1.35! root 101: #ifdef USE_VRAM_THREAD
1.1.1.14 root 102: static CRITICAL_SECTION vram_crit_sect;
103: #else
104: #define vram_flush()
1.1.1.12 root 105: #endif
106:
1.1.1.14 root 107: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
108: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
109:
110: void change_console_size(int width, int height);
111: void clear_scr_buffer(WORD attr);
112:
113: static UINT32 vram_length_char = 0, vram_length_attr = 0;
114: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
115: static COORD vram_coord_char, vram_coord_attr;
116:
1.1.1.28 root 117: char temp_file_path[MAX_PATH];
118: bool temp_file_created = false;
119:
1.1.1.14 root 120: bool ignore_illegal_insn = false;
121: bool limit_max_memory = false;
122: bool no_windows = false;
123: bool stay_busy = false;
1.1.1.19 root 124: bool support_ems = false;
125: #ifdef SUPPORT_XMS
126: bool support_xms = false;
127: #endif
1.1.1.29 root 128: int sio_port_number[4] = {0, 0, 0, 0};
1.1.1.14 root 129:
130: BOOL is_vista_or_later;
131:
1.1.1.35! root 132: #define UPDATE_OPS 16384
! 133: #define REQUEST_HARDWRE_UPDATE() { \
! 134: update_ops = UPDATE_OPS - 1; \
! 135: }
! 136: UINT32 update_ops = 0;
! 137: UINT32 idle_ops = 0;
! 138:
1.1.1.14 root 139: inline void maybe_idle()
140: {
141: // if it appears to be in a tight loop, assume waiting for input
142: // allow for one updated video character, for a spinning cursor
1.1.1.35! root 143: if(!stay_busy && idle_ops < 1024 && vram_length_char <= 1 && vram_length_attr <= 1) {
1.1.1.14 root 144: Sleep(10);
1.1.1.35! root 145: REQUEST_HARDWRE_UPDATE();
1.1.1.14 root 146: }
1.1.1.35! root 147: idle_ops = 0;
1.1.1.14 root 148: }
1.1.1.12 root 149:
1.1 root 150: /* ----------------------------------------------------------------------------
1.1.1.3 root 151: MAME i86/i386
1.1 root 152: ---------------------------------------------------------------------------- */
153:
1.1.1.10 root 154: #ifndef __BIG_ENDIAN__
1.1 root 155: #define LSB_FIRST
1.1.1.10 root 156: #endif
1.1 root 157:
158: #ifndef INLINE
159: #define INLINE inline
160: #endif
161: #define U64(v) UINT64(v)
162:
163: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
164: #define logerror(...)
165: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
166: #define popmessage(...)
167:
168: /*****************************************************************************/
1.1.1.10 root 169: /* src/emu/devcpu.h */
170:
171: // CPU interface functions
172: #define CPU_INIT_NAME(name) cpu_init_##name
173: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
174: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
175:
176: #define CPU_RESET_NAME(name) cpu_reset_##name
177: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
178: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
179:
180: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
181: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
182: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
183:
184: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
185: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
186: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
187:
188: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
189: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
190: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
191:
1.1.1.14 root 192: #define CPU_MODEL_STR(name) #name
193: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
194:
1.1.1.10 root 195: /*****************************************************************************/
196: /* src/emu/didisasm.h */
197:
198: // Disassembler constants
199: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
200: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
201: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
202: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
203: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
204: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
205:
206: /*****************************************************************************/
1.1 root 207: /* src/emu/diexec.h */
208:
209: // I/O line states
210: enum line_state
211: {
212: CLEAR_LINE = 0, // clear (a fired or held) line
213: ASSERT_LINE, // assert an interrupt immediately
214: HOLD_LINE, // hold interrupt line until acknowledged
215: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
216: };
217:
218: // I/O line definitions
219: enum
220: {
221: INPUT_LINE_IRQ = 0,
222: INPUT_LINE_NMI
223: };
224:
225: /*****************************************************************************/
1.1.1.10 root 226: /* src/emu/dimemory.h */
1.1 root 227:
1.1.1.10 root 228: // Translation intentions
229: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
230: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
231: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
232:
233: const int TRANSLATE_READ = 0; // translate for read
234: const int TRANSLATE_WRITE = 1; // translate for write
235: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
236: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
237: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
238: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
239: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
240: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
241: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 242:
1.1.1.10 root 243: /*****************************************************************************/
244: /* src/emu/emucore.h */
1.1 root 245:
1.1.1.10 root 246: // constants for expression endianness
247: enum endianness_t
248: {
249: ENDIANNESS_LITTLE,
250: ENDIANNESS_BIG
251: };
1.1 root 252:
1.1.1.10 root 253: // declare native endianness to be one or the other
254: #ifdef LSB_FIRST
255: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
256: #else
257: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
258: #endif
259:
260: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
261: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
262:
263: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
264: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
265:
266: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
267: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 268:
269: /*****************************************************************************/
270: /* src/emu/memory.h */
271:
1.1.1.10 root 272: // address spaces
273: enum address_spacenum
274: {
275: AS_0, // first address space
276: AS_1, // second address space
277: AS_2, // third address space
278: AS_3, // fourth address space
279: ADDRESS_SPACES, // maximum number of address spaces
280:
281: // alternate address space names for common use
282: AS_PROGRAM = AS_0, // program address space
283: AS_DATA = AS_1, // data address space
284: AS_IO = AS_2 // I/O address space
285: };
286:
1.1 root 287: // offsets and addresses are 32-bit (for now...)
1.1.1.30 root 288: //typedef UINT32 offs_t;
1.1 root 289:
290: // read accessors
291: UINT8 read_byte(offs_t byteaddress)
1.1.1.33 root 292: #ifdef USE_DEBUGGER
293: {
294: if(now_debugging) {
295: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
296: if(rd_break_point.table[i].status == 1) {
297: if(byteaddress == rd_break_point.table[i].addr) {
298: rd_break_point.hit = i + 1;
299: now_suspended = true;
300: break;
301: }
302: }
303: }
304: }
305: return(debugger_read_byte(byteaddress));
306: }
307: UINT8 debugger_read_byte(offs_t byteaddress)
308: #endif
1.1 root 309: {
1.1.1.4 root 310: #if defined(HAS_I386)
1.1 root 311: if(byteaddress < MAX_MEM) {
312: return mem[byteaddress];
1.1.1.3 root 313: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
314: // return read_byte(byteaddress & 0xfffff);
1.1 root 315: }
316: return 0;
1.1.1.4 root 317: #else
318: return mem[byteaddress];
319: #endif
1.1 root 320: }
321:
322: UINT16 read_word(offs_t byteaddress)
1.1.1.33 root 323: #ifdef USE_DEBUGGER
324: {
325: if(now_debugging) {
326: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
327: if(rd_break_point.table[i].status == 1) {
328: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 2) {
329: rd_break_point.hit = i + 1;
330: now_suspended = true;
331: break;
332: }
333: }
334: }
335: }
336: return(debugger_read_word(byteaddress));
337: }
338: UINT16 debugger_read_word(offs_t byteaddress)
339: #endif
1.1 root 340: {
1.1.1.14 root 341: if(byteaddress == 0x41c) {
342: // pointer to first free slot in keyboard buffer
343: // XXX: the buffer itself doesn't actually exist in DOS memory
1.1.1.35! root 344: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 345: #ifdef USE_SERVICE_THREAD
! 346: EnterCriticalSection(&key_buf_crit_sect);
! 347: #endif
! 348: int count = key_buf_char->count();
! 349: #ifdef USE_SERVICE_THREAD
! 350: LeaveCriticalSection(&key_buf_crit_sect);
! 351: #endif
! 352: if(count == 0) {
1.1.1.32 root 353: maybe_idle();
354: }
1.1.1.35! root 355: return (UINT16)count;
1.1.1.14 root 356: }
1.1.1.32 root 357: return 0;
1.1.1.14 root 358: }
1.1.1.4 root 359: #if defined(HAS_I386)
1.1 root 360: if(byteaddress < MAX_MEM - 1) {
361: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 362: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
363: // return read_word(byteaddress & 0xfffff);
1.1 root 364: }
365: return 0;
1.1.1.4 root 366: #else
367: return *(UINT16 *)(mem + byteaddress);
368: #endif
1.1 root 369: }
370:
371: UINT32 read_dword(offs_t byteaddress)
1.1.1.33 root 372: #ifdef USE_DEBUGGER
373: {
374: if(now_debugging) {
375: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
376: if(rd_break_point.table[i].status == 1) {
377: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 4) {
378: rd_break_point.hit = i + 1;
379: now_suspended = true;
380: break;
381: }
382: }
383: }
384: }
385: return(debugger_read_dword(byteaddress));
386: }
387: UINT32 debugger_read_dword(offs_t byteaddress)
388: #endif
1.1 root 389: {
1.1.1.4 root 390: #if defined(HAS_I386)
1.1 root 391: if(byteaddress < MAX_MEM - 3) {
392: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 393: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
394: // return read_dword(byteaddress & 0xfffff);
1.1 root 395: }
396: return 0;
1.1.1.4 root 397: #else
398: return *(UINT32 *)(mem + byteaddress);
399: #endif
1.1 root 400: }
401:
402: // write accessors
1.1.1.35! root 403: #ifdef USE_VRAM_THREAD
1.1.1.14 root 404: void vram_flush_char()
405: {
406: if(vram_length_char != 0) {
407: DWORD num;
1.1.1.23 root 408: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 409: vram_length_char = vram_last_length_char = 0;
410: }
411: }
412:
413: void vram_flush_attr()
414: {
415: if(vram_length_attr != 0) {
416: DWORD num;
1.1.1.23 root 417: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 418: vram_length_attr = vram_last_length_attr = 0;
419: }
420: }
421:
422: void vram_flush()
423: {
424: if(vram_length_char != 0 || vram_length_attr != 0) {
425: EnterCriticalSection(&vram_crit_sect);
426: vram_flush_char();
427: vram_flush_attr();
428: LeaveCriticalSection(&vram_crit_sect);
429: }
430: }
431: #endif
432:
433: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 434: {
1.1.1.35! root 435: #ifdef USE_VRAM_THREAD
1.1.1.14 root 436: static offs_t first_offset_char, last_offset_char;
437:
438: if(vram_length_char != 0) {
439: if(offset <= last_offset_char && offset >= first_offset_char) {
440: scr_char[(offset - first_offset_char) >> 1] = data;
441: return;
442: }
443: if(offset != last_offset_char + 2) {
444: vram_flush_char();
445: }
446: }
447: if(vram_length_char == 0) {
448: first_offset_char = offset;
449: vram_coord_char.X = (offset >> 1) % scr_width;
450: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
451: }
452: scr_char[vram_length_char++] = data;
453: last_offset_char = offset;
454: #else
1.1.1.8 root 455: COORD co;
456: DWORD num;
457:
1.1.1.14 root 458: co.X = (offset >> 1) % scr_width;
459: co.Y = (offset >> 1) / scr_width;
460: scr_char[0] = data;
1.1.1.23 root 461: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 462: #endif
463: }
464:
465: void write_text_vram_attr(offs_t offset, UINT8 data)
466: {
1.1.1.35! root 467: #ifdef USE_VRAM_THREAD
1.1.1.14 root 468: static offs_t first_offset_attr, last_offset_attr;
469:
470: if(vram_length_attr != 0) {
471: if(offset <= last_offset_attr && offset >= first_offset_attr) {
472: scr_attr[(offset - first_offset_attr) >> 1] = data;
473: return;
474: }
475: if(offset != last_offset_attr + 2) {
476: vram_flush_attr();
477: }
478: }
479: if(vram_length_attr == 0) {
480: first_offset_attr = offset;
481: vram_coord_attr.X = (offset >> 1) % scr_width;
482: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
483: }
484: scr_attr[vram_length_attr++] = data;
485: last_offset_attr = offset;
486: #else
487: COORD co;
488: DWORD num;
1.1.1.8 root 489:
1.1.1.14 root 490: co.X = (offset >> 1) % scr_width;
491: co.Y = (offset >> 1) / scr_width;
492: scr_attr[0] = data;
1.1.1.23 root 493: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 494: #endif
495: }
496:
497: void write_text_vram_byte(offs_t offset, UINT8 data)
498: {
1.1.1.35! root 499: #ifdef USE_VRAM_THREAD
1.1.1.14 root 500: EnterCriticalSection(&vram_crit_sect);
1.1.1.35! root 501: #endif
1.1.1.8 root 502: if(offset & 1) {
1.1.1.14 root 503: write_text_vram_attr(offset, data);
1.1.1.8 root 504: } else {
1.1.1.14 root 505: write_text_vram_char(offset, data);
1.1.1.8 root 506: }
1.1.1.35! root 507: #ifdef USE_VRAM_THREAD
1.1.1.14 root 508: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35! root 509: #endif
1.1.1.8 root 510: }
511:
512: void write_text_vram_word(offs_t offset, UINT16 data)
513: {
1.1.1.35! root 514: #ifdef USE_VRAM_THREAD
1.1.1.14 root 515: EnterCriticalSection(&vram_crit_sect);
1.1.1.35! root 516: #endif
1.1.1.8 root 517: if(offset & 1) {
1.1.1.14 root 518: write_text_vram_attr(offset , (data ) & 0xff);
519: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 520: } else {
1.1.1.14 root 521: write_text_vram_char(offset , (data ) & 0xff);
522: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 523: }
1.1.1.35! root 524: #ifdef USE_VRAM_THREAD
1.1.1.14 root 525: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35! root 526: #endif
1.1.1.8 root 527: }
528:
529: void write_text_vram_dword(offs_t offset, UINT32 data)
530: {
1.1.1.35! root 531: #ifdef USE_VRAM_THREAD
1.1.1.14 root 532: EnterCriticalSection(&vram_crit_sect);
1.1.1.35! root 533: #endif
1.1.1.8 root 534: if(offset & 1) {
1.1.1.14 root 535: write_text_vram_attr(offset , (data ) & 0xff);
536: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
537: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
538: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
539: } else {
540: write_text_vram_char(offset , (data ) & 0xff);
541: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
542: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
543: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 544: }
1.1.1.35! root 545: #ifdef USE_VRAM_THREAD
1.1.1.14 root 546: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35! root 547: #endif
1.1.1.8 root 548: }
549:
1.1 root 550: void write_byte(offs_t byteaddress, UINT8 data)
1.1.1.33 root 551: #ifdef USE_DEBUGGER
552: {
553: if(now_debugging) {
554: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
555: if(wr_break_point.table[i].status == 1) {
556: if(byteaddress == wr_break_point.table[i].addr) {
557: wr_break_point.hit = i + 1;
558: now_suspended = true;
559: break;
560: }
561: }
562: }
563: }
564: debugger_write_byte(byteaddress, data);
565: }
566: void debugger_write_byte(offs_t byteaddress, UINT8 data)
567: #endif
1.1 root 568: {
1.1.1.8 root 569: if(byteaddress < MEMORY_END) {
1.1.1.3 root 570: mem[byteaddress] = data;
1.1.1.8 root 571: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 572: if(!restore_console_on_exit) {
573: change_console_size(scr_width, scr_height);
1.1.1.12 root 574: }
1.1.1.8 root 575: write_text_vram_byte(byteaddress - text_vram_top_address, data);
576: mem[byteaddress] = data;
577: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
578: if(int_10h_feh_called && !int_10h_ffh_called) {
579: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 580: }
581: mem[byteaddress] = data;
1.1.1.4 root 582: #if defined(HAS_I386)
1.1.1.3 root 583: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 584: #else
585: } else {
586: #endif
1.1.1.3 root 587: mem[byteaddress] = data;
1.1 root 588: }
589: }
590:
591: void write_word(offs_t byteaddress, UINT16 data)
1.1.1.33 root 592: #ifdef USE_DEBUGGER
593: {
594: if(now_debugging) {
595: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
596: if(wr_break_point.table[i].status == 1) {
597: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 2) {
598: wr_break_point.hit = i + 1;
599: now_suspended = true;
600: break;
601: }
602: }
603: }
604: }
605: debugger_write_word(byteaddress, data);
606: }
607: void debugger_write_word(offs_t byteaddress, UINT16 data)
608: #endif
1.1 root 609: {
1.1.1.8 root 610: if(byteaddress < MEMORY_END) {
1.1.1.14 root 611: if(byteaddress == 0x450 + mem[0x462] * 2) {
612: COORD co;
613: co.X = data & 0xff;
614: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 615: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 616: }
1.1.1.3 root 617: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 618: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 619: if(!restore_console_on_exit) {
620: change_console_size(scr_width, scr_height);
1.1.1.12 root 621: }
1.1.1.8 root 622: write_text_vram_word(byteaddress - text_vram_top_address, data);
623: *(UINT16 *)(mem + byteaddress) = data;
624: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
625: if(int_10h_feh_called && !int_10h_ffh_called) {
626: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 627: }
628: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 629: #if defined(HAS_I386)
1.1.1.3 root 630: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 631: #else
632: } else {
633: #endif
1.1.1.3 root 634: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 635: }
636: }
637:
638: void write_dword(offs_t byteaddress, UINT32 data)
1.1.1.33 root 639: #ifdef USE_DEBUGGER
640: {
641: if(now_debugging) {
642: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
643: if(wr_break_point.table[i].status == 1) {
644: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 4) {
645: wr_break_point.hit = i + 1;
646: now_suspended = true;
647: break;
648: }
649: }
650: }
651: }
652: debugger_write_dword(byteaddress, data);
653: }
654: void debugger_write_dword(offs_t byteaddress, UINT32 data)
655: #endif
1.1 root 656: {
1.1.1.8 root 657: if(byteaddress < MEMORY_END) {
1.1.1.3 root 658: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 659: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 660: if(!restore_console_on_exit) {
661: change_console_size(scr_width, scr_height);
1.1.1.12 root 662: }
1.1.1.8 root 663: write_text_vram_dword(byteaddress - text_vram_top_address, data);
664: *(UINT32 *)(mem + byteaddress) = data;
665: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
666: if(int_10h_feh_called && !int_10h_ffh_called) {
667: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 668: }
669: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 670: #if defined(HAS_I386)
1.1.1.3 root 671: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 672: #else
673: } else {
674: #endif
1.1.1.3 root 675: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 676: }
677: }
678:
679: #define read_decrypted_byte read_byte
680: #define read_decrypted_word read_word
681: #define read_decrypted_dword read_dword
682:
1.1.1.3 root 683: #define read_raw_byte read_byte
684: #define write_raw_byte write_byte
685:
686: #define read_word_unaligned read_word
687: #define write_word_unaligned write_word
688:
689: #define read_io_word_unaligned read_io_word
690: #define write_io_word_unaligned write_io_word
691:
1.1 root 692: UINT8 read_io_byte(offs_t byteaddress);
693: UINT16 read_io_word(offs_t byteaddress);
694: UINT32 read_io_dword(offs_t byteaddress);
695:
696: void write_io_byte(offs_t byteaddress, UINT8 data);
697: void write_io_word(offs_t byteaddress, UINT16 data);
698: void write_io_dword(offs_t byteaddress, UINT32 data);
699:
700: /*****************************************************************************/
701: /* src/osd/osdcomm.h */
702:
703: /* Highly useful macro for compile-time knowledge of an array size */
704: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
705:
1.1.1.3 root 706: #if defined(HAS_I386)
1.1.1.10 root 707: static CPU_TRANSLATE(i386);
708: #include "mame/lib/softfloat/softfloat.c"
709: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 710: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 711: #elif defined(HAS_I286)
1.1.1.10 root 712: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 713: #else
1.1.1.10 root 714: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 715: #endif
1.1.1.33 root 716: #ifdef USE_DEBUGGER
1.1.1.10 root 717: #include "mame/emu/cpu/i386/i386dasm.c"
1.1 root 718: #endif
719:
1.1.1.3 root 720: #if defined(HAS_I386)
721: #define SREG(x) m_sreg[x].selector
722: #define SREG_BASE(x) m_sreg[x].base
723: int cpu_type, cpu_step;
724: #else
725: #define REG8(x) m_regs.b[x]
726: #define REG16(x) m_regs.w[x]
727: #define SREG(x) m_sregs[x]
728: #define SREG_BASE(x) m_base[x]
1.1.1.33 root 729: #define m_eip (m_pc - m_base[CS])
1.1.1.3 root 730: #define m_CF m_CarryVal
731: #define m_a20_mask AMASK
732: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
733: #if defined(HAS_I286)
734: #define i386_set_a20_line(x) i80286_set_a20_line(x)
735: #else
736: #define i386_set_a20_line(x)
737: #endif
738: #define i386_set_irq_line(x, y) set_irq_line(x, y)
739: #endif
1.1 root 740:
741: void i386_jmp_far(UINT16 selector, UINT32 address)
742: {
1.1.1.3 root 743: #if defined(HAS_I386)
1.1 root 744: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 745: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 746: } else {
1.1.1.3 root 747: SREG(CS) = selector;
748: m_performed_intersegment_jump = 1;
749: i386_load_segment_descriptor(CS);
750: m_eip = address;
751: CHANGE_PC(m_eip);
1.1 root 752: }
1.1.1.3 root 753: #elif defined(HAS_I286)
754: i80286_code_descriptor(selector, address, 1);
755: #else
756: SREG(CS) = selector;
757: i386_load_segment_descriptor(CS);
758: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
759: #endif
1.1 root 760: }
761:
1.1.1.35! root 762: #ifdef USE_SERVICE_THREAD
1.1.1.24 root 763: void i386_call_far(UINT16 selector, UINT32 address)
764: {
765: #if defined(HAS_I386)
766: if(PROTECTED_MODE && !V8086_MODE) {
767: i386_protected_mode_call(selector, address, 1, m_operand_size);
768: } else {
769: PUSH16(SREG(CS));
770: PUSH16(m_eip);
771: SREG(CS) = selector;
772: m_performed_intersegment_jump = 1;
773: i386_load_segment_descriptor(CS);
774: m_eip = address;
775: CHANGE_PC(m_eip);
776: }
777: #else
778: UINT16 ip = m_pc - SREG_BASE(CS);
779: UINT16 cs = SREG(CS);
780: #if defined(HAS_I286)
781: i80286_code_descriptor(selector, address, 2);
782: #else
783: SREG(CS) = selector;
784: i386_load_segment_descriptor(CS);
785: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
786: #endif
787: PUSH(cs);
788: PUSH(ip);
789: CHANGE_PC(m_pc);
790: #endif
791: }
1.1.1.35! root 792: #endif
1.1.1.24 root 793:
1.1.1.29 root 794: UINT16 i386_read_stack()
795: {
796: #if defined(HAS_I386)
797: UINT32 ea, new_esp;
798: if( STACK_32BIT ) {
799: new_esp = REG32(ESP) + 2;
800: ea = i386_translate(SS, new_esp - 2, 0);
801: } else {
802: new_esp = REG16(SP) + 2;
803: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
804: }
805: return READ16(ea);
806: #else
807: UINT16 sp = m_regs.w[SP] + 2;
808: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
809: #endif
810: }
811:
1.1 root 812: /* ----------------------------------------------------------------------------
1.1.1.33 root 813: debugger
814: ---------------------------------------------------------------------------- */
815:
816: #ifdef USE_DEBUGGER
817: #define TELNET_BLUE 0x0004 // text color contains blue.
818: #define TELNET_GREEN 0x0002 // text color contains green.
819: #define TELNET_RED 0x0001 // text color contains red.
820: #define TELNET_INTENSITY 0x0008 // text color is intensified.
821:
822: int svr_socket = 0;
823: int cli_socket = 0;
824:
825: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error);
826:
827: void debugger_init()
828: {
829: now_debugging = false;
830: now_going = false;
831: now_suspended = false;
832: force_suspend = false;
833:
834: memset(&break_point, 0, sizeof(break_point_t));
835: memset(&rd_break_point, 0, sizeof(break_point_t));
836: memset(&wr_break_point, 0, sizeof(break_point_t));
837: memset(&in_break_point, 0, sizeof(break_point_t));
838: memset(&out_break_point, 0, sizeof(break_point_t));
839: memset(&int_break_point, 0, sizeof(int_break_point_t));
840: }
841:
842: void telnet_send(char *string)
843: {
844: char buffer[8192], *ptr;
845: strcpy(buffer, string);
846: while((ptr = strstr(buffer, "\n")) != NULL) {
847: char tmp[8192];
848: *ptr = '\0';
849: sprintf(tmp, "%s\033E%s", buffer, ptr + 1);
850: strcpy(buffer, tmp);
851: }
852:
853: int len = strlen(buffer), res;
854: ptr = buffer;
855: while(len > 0) {
856: if((res = send(cli_socket, ptr, len, 0)) > 0) {
857: len -= res;
858: ptr += res;
859: }
860: }
861: }
862:
863: void telnet_command(const char *format, ...)
864: {
865: char buffer[1024];
866: va_list ap;
867: va_start(ap, format);
868: vsprintf(buffer, format, ap);
869: va_end(ap);
870:
871: telnet_send(buffer);
872: }
873:
874: void telnet_printf(const char *format, ...)
875: {
876: char buffer[1024];
877: va_list ap;
878: va_start(ap, format);
879: vsprintf(buffer, format, ap);
880: va_end(ap);
881:
882: if(fp_debugger != NULL) {
883: fprintf(fp_debugger, "%s", buffer);
884: }
885: telnet_send(buffer);
886: }
887:
888: bool telnet_gets(char *str, int n)
889: {
890: char buffer[1024];
891: int ptr = 0;
892:
893: telnet_command("\033[12l"); // local echo on
894: telnet_command("\033[2l"); // key unlock
895:
896: while(!m_halted) {
897: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
898:
899: if(len > 0 && buffer[0] != 0xff) {
900: for(int i = 0; i < len; i++) {
901: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
902: str[ptr] = 0;
903: telnet_command("\033[2h"); // key lock
904: telnet_command("\033[12h"); // local echo off
905: return(!m_halted);
906: } else if(buffer[i] == 0x08) {
907: if(ptr > 0) {
908: telnet_command("\033[0K"); // erase from cursor position
909: ptr--;
910: } else {
911: telnet_command("\033[1C"); // move cursor forward
912: }
913: } else if(ptr < n - 1) {
914: if (buffer[i] >= 0x20 && buffer[i] <= 0x7e) {
915: str[ptr++] = buffer[i];
916: }
917: } else {
918: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position
919: }
920: }
921: } else if(len == -1) {
922: if(WSAGetLastError() != WSAEWOULDBLOCK) {
923: return(false);
924: }
925: } else if(len == 0) {
926: return(false);
927: }
928: Sleep(10);
929: }
930: return(!m_halted);
931: }
932:
933: bool telnet_kbhit()
934: {
935: char buffer[1024];
936:
937: if(!m_halted) {
938: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
939:
940: if(len > 0) {
941: for(int i = 0; i < len; i++) {
942: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
943: return(true);
944: }
945: }
946: } else if(len == 0) {
947: return(true); // disconnected
948: }
949: }
950: return(false);
951: }
952:
953: bool telnet_disconnected()
954: {
955: char buffer[1024];
956: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
957:
958: if(len == 0) {
959: return(true);
960: } else if(len == -1) {
961: if(WSAGetLastError() != WSAEWOULDBLOCK) {
962: return(true);
963: }
964: }
965: return(false);
966: }
967:
968: void telnet_set_color(int color)
969: {
970: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7));
971: }
972:
973: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip)
974: {
975: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1));
976: UINT8 ops[16];
977: for(int i = 0; i < 16; i++) {
978: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK);
979: }
980: UINT8 *oprom = ops;
981:
982: #if defined(HAS_I386)
983: if(m_operand_size) {
984: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK);
985: } else
986: #endif
987: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK);
988: }
989:
990: void debugger_regs_info(char *buffer)
991: {
992: #if defined(HAS_I386)
993: UINT32 flags = get_flags();
994: #else
995: UINT32 flags = CompressFlags();
996: #endif
997: #if defined(HAS_I386)
998: if(m_operand_size) {
999: 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",
1000: 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),
1001: PROTECTED_MODE ? "PE" : "--",
1002: (flags & 0x40000) ? 'A' : '-',
1003: (flags & 0x20000) ? 'V' : '-',
1004: (flags & 0x10000) ? 'R' : '-',
1005: (flags & 0x04000) ? 'N' : '-',
1006: (flags & 0x02000) ? '1' : '0',
1007: (flags & 0x01000) ? '1' : '0',
1008: (flags & 0x00800) ? 'O' : '-',
1009: (flags & 0x00400) ? 'D' : '-',
1010: (flags & 0x00200) ? 'I' : '-',
1011: (flags & 0x00100) ? 'T' : '-',
1012: (flags & 0x00080) ? 'S' : '-',
1013: (flags & 0x00040) ? 'Z' : '-',
1014: (flags & 0x00010) ? 'A' : '-',
1015: (flags & 0x00004) ? 'P' : '-',
1016: (flags & 0x00001) ? 'C' : '-');
1017: } else {
1018: #endif
1019: 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",
1020: 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),
1021: #if defined(HAS_I386)
1022: PROTECTED_MODE ? "PE" : "--",
1023: #else
1024: "--",
1025: #endif
1026: (flags & 0x40000) ? 'A' : '-',
1027: (flags & 0x20000) ? 'V' : '-',
1028: (flags & 0x10000) ? 'R' : '-',
1029: (flags & 0x04000) ? 'N' : '-',
1030: (flags & 0x02000) ? '1' : '0',
1031: (flags & 0x01000) ? '1' : '0',
1032: (flags & 0x00800) ? 'O' : '-',
1033: (flags & 0x00400) ? 'D' : '-',
1034: (flags & 0x00200) ? 'I' : '-',
1035: (flags & 0x00100) ? 'T' : '-',
1036: (flags & 0x00080) ? 'S' : '-',
1037: (flags & 0x00040) ? 'Z' : '-',
1038: (flags & 0x00010) ? 'A' : '-',
1039: (flags & 0x00004) ? 'P' : '-',
1040: (flags & 0x00001) ? 'C' : '-');
1041: #if defined(HAS_I386)
1042: }
1043: #endif
1044: }
1045:
1046: void debugger_process_info(char *buffer)
1047: {
1048: UINT16 psp_seg = current_psp;
1049: process_t *process;
1050: bool check[0x10000] = {0};
1051:
1052: buffer[0] = '\0';
1053:
1054: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) {
1055: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1056: char *file = process->module_path, *s;
1057: char tmp[8192];
1058:
1059: while((s = strstr(file, "\\")) != NULL) {
1060: file = s + 1;
1061: }
1062: 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));
1063: strcat(tmp, buffer);
1064: strcpy(buffer, tmp);
1065:
1066: check[psp_seg] = true;
1067: psp_seg = psp->parent_psp;
1068: }
1069: }
1070:
1071: UINT32 debugger_get_val(const char *str)
1072: {
1073: char tmp[1024];
1074:
1075: if(str == NULL || strlen(str) == 0) {
1076: return(0);
1077: }
1078: strcpy(tmp, str);
1079:
1080: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') {
1081: // ank
1082: return(tmp[1] & 0xff);
1083: } else if(tmp[0] == '%') {
1084: // decimal
1085: return(strtoul(tmp + 1, NULL, 10));
1086: }
1087: return(strtoul(tmp, NULL, 16));
1088: }
1089:
1090: UINT32 debugger_get_seg(const char *str, UINT32 val)
1091: {
1092: char tmp[1024], *s;
1093:
1094: if(str == NULL || strlen(str) == 0) {
1095: return(val);
1096: }
1097: strcpy(tmp, str);
1098:
1099: if((s = strstr(tmp, ":")) != NULL) {
1100: // 0000:0000
1101: *s = '\0';
1102: return(debugger_get_val(tmp));
1103: }
1104: return(val);
1105: }
1106:
1107: UINT32 debugger_get_ofs(const char *str)
1108: {
1109: char tmp[1024], *s;
1110:
1111: if(str == NULL || strlen(str) == 0) {
1112: return(0);
1113: }
1114: strcpy(tmp, str);
1115:
1116: if((s = strstr(tmp, ":")) != NULL) {
1117: // 0000:0000
1118: return(debugger_get_val(s + 1));
1119: }
1120: return(debugger_get_val(tmp));
1121: }
1122:
1123: void debugger_main()
1124: {
1125: telnet_command("\033[20h"); // cr-lf
1126:
1127: force_suspend = true;
1128: now_going = false;
1129: now_debugging = true;
1130: Sleep(100);
1131:
1132: if(!m_halted && !now_suspended) {
1133: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1134: telnet_printf("waiting until cpu is suspended...\n");
1135: }
1136: while(!m_halted && !now_suspended) {
1137: if(telnet_disconnected()) {
1138: break;
1139: }
1140: Sleep(10);
1141: }
1142:
1143: char buffer[8192];
1144:
1145: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1146: debugger_process_info(buffer);
1147: telnet_printf("%s", buffer);
1148: debugger_regs_info(buffer);
1149: telnet_printf("%s", buffer);
1150: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1151: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip);
1152: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1153: debugger_dasm(buffer, SREG(CS), m_eip);
1154: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1155: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1156:
1157: #define MAX_COMMAND_LEN 64
1158:
1159: char command[MAX_COMMAND_LEN + 1];
1160: char prev_command[MAX_COMMAND_LEN + 1] = {0};
1161:
1162: UINT32 data_seg = SREG(DS);
1163: UINT32 data_ofs = 0;
1164: UINT32 dasm_seg = SREG(CS);
1165: UINT32 dasm_ofs = m_eip;
1166:
1167: while(!m_halted) {
1168: telnet_printf("- ");
1169: command[0] = '\0';
1170:
1171: if(fi_debugger != NULL) {
1172: while(command[0] == '\0') {
1173: if(fgets(command, sizeof(command), fi_debugger) == NULL) {
1174: break;
1175: }
1176: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) {
1177: command[strlen(command) - 1] = '\0';
1178: }
1179: }
1180: if(command[0] != '\0') {
1181: telnet_command("%s\n", command);
1182: }
1183: }
1184: if(command[0] == '\0') {
1185: if(!telnet_gets(command, sizeof(command))) {
1186: break;
1187: }
1188: }
1189: if(command[0] == '\0') {
1190: strcpy(command, prev_command);
1191: } else {
1192: strcpy(prev_command, command);
1193: }
1194: if(fp_debugger != NULL) {
1195: fprintf(fp_debugger, "%s\n", command);
1196: }
1197:
1198: if(!m_halted && command[0] != 0) {
1199: char *params[32], *token = NULL;
1200: int num = 0;
1201:
1202: if((token = strtok(command, " ")) != NULL) {
1203: params[num++] = token;
1204: while(num < 32 && (token = strtok(NULL, " ")) != NULL) {
1205: params[num++] = token;
1206: }
1207: }
1208: if(stricmp(params[0], "D") == 0) {
1209: if(num <= 3) {
1210: if(num >= 2) {
1211: data_seg = debugger_get_seg(params[1], data_seg);
1212: data_ofs = debugger_get_ofs(params[1]);
1213: }
1214: UINT32 end_seg = data_seg;
1215: UINT32 end_ofs = data_ofs + 8 * 16 - 1;
1216: if(num == 3) {
1217: end_seg = debugger_get_seg(params[2], data_seg);
1218: end_ofs = debugger_get_ofs(params[2]);
1219: }
1220: UINT64 start_addr = (data_seg << 4) + data_ofs;
1221: UINT64 end_addr = (end_seg << 4) + end_ofs;
1222: // bool sjis = false;
1223:
1224: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) {
1225: if((addr & 0x0f) == 0) {
1226: if((data_ofs = addr - (data_seg << 4)) > 0xffff) {
1227: data_seg += 0x1000;
1228: data_ofs -= 0x10000;
1229: }
1230: telnet_printf("%06X:%04X ", data_seg, data_ofs);
1231: memset(buffer, 0, sizeof(buffer));
1232: }
1233: if(addr < start_addr || addr > end_addr) {
1234: telnet_printf(" ");
1235: buffer[addr & 0x0f] = ' ';
1236: } else {
1237: UINT8 data = debugger_read_byte(addr & ADDR_MASK);
1238: telnet_printf(" %02X", data);
1239: // if(sjis) {
1240: // buffer[addr & 0x0f] = data;
1241: // sjis = false;
1242: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) {
1243: // buffer[addr & 0x0f] = data;
1244: // sjis = true;
1245: // } else
1246: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) {
1247: buffer[addr & 0x0f] = data;
1248: } else {
1249: buffer[addr & 0x0f] = '.';
1250: }
1251: }
1252: if((addr & 0x0f) == 0x0f) {
1253: telnet_printf(" %s\n", buffer);
1254: }
1255: }
1256: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) {
1257: data_seg += 0x1000;
1258: data_ofs -= 0x10000;
1259: }
1260: prev_command[1] = '\0'; // remove parameters to dump continuously
1261: } else {
1262: telnet_printf("invalid parameter number\n");
1263: }
1264: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) {
1265: if(num >= 3) {
1266: UINT32 seg = debugger_get_seg(params[1], data_seg);
1267: UINT32 ofs = debugger_get_ofs(params[1]);
1268: for(int i = 2, j = 0; i < num; i++, j++) {
1269: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff);
1270: }
1271: } else {
1272: telnet_printf("invalid parameter number\n");
1273: }
1274: } else if(stricmp(params[0], "EW") == 0) {
1275: if(num >= 3) {
1276: UINT32 seg = debugger_get_seg(params[1], data_seg);
1277: UINT32 ofs = debugger_get_ofs(params[1]);
1278: for(int i = 2, j = 0; i < num; i++, j += 2) {
1279: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff);
1280: }
1281: } else {
1282: telnet_printf("invalid parameter number\n");
1283: }
1284: } else if(stricmp(params[0], "ED") == 0) {
1285: if(num >= 3) {
1286: UINT32 seg = debugger_get_seg(params[1], data_seg);
1287: UINT32 ofs = debugger_get_ofs(params[1]);
1288: for(int i = 2, j = 0; i < num; i++, j += 4) {
1289: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]));
1290: }
1291: } else {
1292: telnet_printf("invalid parameter number\n");
1293: }
1294: } else if(stricmp(params[0], "EA") == 0) {
1295: if(num >= 3) {
1296: UINT32 seg = debugger_get_seg(params[1], data_seg);
1297: UINT32 ofs = debugger_get_ofs(params[1]);
1298: strcpy(buffer, prev_command);
1299: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) {
1300: int len = strlen(token);
1301: for(int i = 0; i < len; i++) {
1302: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff);
1303: }
1304: } else {
1305: telnet_printf("invalid parameter\n");
1306: }
1307: } else {
1308: telnet_printf("invalid parameter number\n");
1309: }
1310: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) {
1311: if(num == 2) {
1312: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff);
1313: } else {
1314: telnet_printf("invalid parameter number\n");
1315: }
1316: } else if(stricmp(params[0], "IW") == 0) {
1317: if(num == 2) {
1318: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff);
1319: } else {
1320: telnet_printf("invalid parameter number\n");
1321: }
1322: } else if(stricmp(params[0], "ID") == 0) {
1323: if(num == 2) {
1324: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1])));
1325: } else {
1326: telnet_printf("invalid parameter number\n");
1327: }
1328: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) {
1329: if(num == 3) {
1330: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff);
1331: } else {
1332: telnet_printf("invalid parameter number\n");
1333: }
1334: } else if(stricmp(params[0], "OW") == 0) {
1335: if(num == 3) {
1336: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff);
1337: } else {
1338: telnet_printf("invalid parameter number\n");
1339: }
1340: } else if(stricmp(params[0], "OD") == 0) {
1341: if(num == 3) {
1342: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2]));
1343: } else {
1344: telnet_printf("invalid parameter number\n");
1345: }
1346: } else if(stricmp(params[0], "R") == 0) {
1347: if(num == 1) {
1348: debugger_regs_info(buffer);
1349: telnet_printf("%s", buffer);
1350: } else if(num == 3) {
1351: #if defined(HAS_I386)
1352: if(stricmp(params[1], "EAX") == 0) {
1353: REG32(EAX) = debugger_get_val(params[2]);
1354: } else if(stricmp(params[1], "EBX") == 0) {
1355: REG32(EBX) = debugger_get_val(params[2]);
1356: } else if(stricmp(params[1], "ECX") == 0) {
1357: REG32(ECX) = debugger_get_val(params[2]);
1358: } else if(stricmp(params[1], "EDX") == 0) {
1359: REG32(EDX) = debugger_get_val(params[2]);
1360: } else if(stricmp(params[1], "ESP") == 0) {
1361: REG32(ESP) = debugger_get_val(params[2]);
1362: } else if(stricmp(params[1], "EBP") == 0) {
1363: REG32(EBP) = debugger_get_val(params[2]);
1364: } else if(stricmp(params[1], "ESI") == 0) {
1365: REG32(ESI) = debugger_get_val(params[2]);
1366: } else if(stricmp(params[1], "EDI") == 0) {
1367: REG32(EDI) = debugger_get_val(params[2]);
1368: } else
1369: #endif
1370: if(stricmp(params[1], "AX") == 0) {
1371: REG16(AX) = debugger_get_val(params[2]);
1372: } else if(stricmp(params[1], "BX") == 0) {
1373: REG16(BX) = debugger_get_val(params[2]);
1374: } else if(stricmp(params[1], "CX") == 0) {
1375: REG16(CX) = debugger_get_val(params[2]);
1376: } else if(stricmp(params[1], "DX") == 0) {
1377: REG16(DX) = debugger_get_val(params[2]);
1378: } else if(stricmp(params[1], "SP") == 0) {
1379: REG16(SP) = debugger_get_val(params[2]);
1380: } else if(stricmp(params[1], "BP") == 0) {
1381: REG16(BP) = debugger_get_val(params[2]);
1382: } else if(stricmp(params[1], "SI") == 0) {
1383: REG16(SI) = debugger_get_val(params[2]);
1384: } else if(stricmp(params[1], "DI") == 0) {
1385: REG16(DI) = debugger_get_val(params[2]);
1386: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) {
1387: #if defined(HAS_I386)
1388: if(m_operand_size) {
1389: m_eip = debugger_get_val(params[2]);
1390: } else {
1391: m_eip = debugger_get_val(params[2]) & 0xffff;
1392: }
1393: CHANGE_PC(m_eip);
1394: #else
1395: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK;
1396: CHANGE_PC(m_pc);
1397: #endif
1398: } else if(stricmp(params[1], "AL") == 0) {
1399: REG8(AL) = debugger_get_val(params[2]);
1400: } else if(stricmp(params[1], "AH") == 0) {
1401: REG8(AH) = debugger_get_val(params[2]);
1402: } else if(stricmp(params[1], "BL") == 0) {
1403: REG8(BL) = debugger_get_val(params[2]);
1404: } else if(stricmp(params[1], "BH") == 0) {
1405: REG8(BH) = debugger_get_val(params[2]);
1406: } else if(stricmp(params[1], "CL") == 0) {
1407: REG8(CL) = debugger_get_val(params[2]);
1408: } else if(stricmp(params[1], "CH") == 0) {
1409: REG8(CH) = debugger_get_val(params[2]);
1410: } else if(stricmp(params[1], "DL") == 0) {
1411: REG8(DL) = debugger_get_val(params[2]);
1412: } else if(stricmp(params[1], "DH") == 0) {
1413: REG8(DH) = debugger_get_val(params[2]);
1414: } else {
1415: telnet_printf("unknown register %s\n", params[1]);
1416: }
1417: } else {
1418: telnet_printf("invalid parameter number\n");
1419: }
1420: } else if(_tcsicmp(params[0], "S") == 0) {
1421: if(num >= 4) {
1422: UINT32 cur_seg = debugger_get_seg(params[1], data_seg);
1423: UINT32 cur_ofs = debugger_get_ofs(params[1]);
1424: UINT32 end_seg = debugger_get_seg(params[2], cur_seg);
1425: UINT32 end_ofs = debugger_get_ofs(params[2]);
1426: UINT8 list[32];
1427:
1428: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1429: list[j] = debugger_get_val(params[i]);
1430: }
1431: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) {
1432: bool found = true;
1433: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1434: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) {
1435: found = false;
1436: break;
1437: }
1438: }
1439: if(found) {
1440: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs);
1441: }
1442: if((cur_ofs += 1) > 0xffff) {
1443: cur_seg += 0x1000;
1444: cur_ofs -= 0x10000;
1445: }
1446: }
1447: } else {
1448: telnet_printf("invalid parameter number\n");
1449: }
1450: } else if(stricmp(params[0], "U") == 0) {
1451: if(num <= 3) {
1452: if(num >= 2) {
1453: dasm_seg = debugger_get_seg(params[1], dasm_seg);
1454: dasm_ofs = debugger_get_ofs(params[1]);
1455: }
1456: if(num == 3) {
1457: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg);
1458: UINT32 end_ofs = debugger_get_ofs(params[2]);
1459:
1460: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) {
1461: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1462: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1463: for(int i = 0; i < len; i++) {
1464: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1465: }
1466: for(int i = len; i < 8; i++) {
1467: telnet_printf(" ");
1468: }
1469: telnet_printf(" %s\n", buffer);
1470: if((dasm_ofs += len) > 0xffff) {
1471: dasm_seg += 0x1000;
1472: dasm_ofs -= 0x10000;
1473: }
1474: }
1475: } else {
1476: for(int i = 0; i < 16; i++) {
1477: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1478: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1479: for(int i = 0; i < len; i++) {
1480: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1481: }
1482: for(int i = len; i < 8; i++) {
1483: telnet_printf(" ");
1484: }
1485: telnet_printf(" %s\n", buffer);
1486: if((dasm_ofs += len) > 0xffff) {
1487: dasm_seg += 0x1000;
1488: dasm_ofs -= 0x10000;
1489: }
1490: }
1491: }
1492: prev_command[1] = '\0'; // remove parameters to disassemble continuously
1493: } else {
1494: telnet_printf("invalid parameter number\n");
1495: }
1496: } else if(stricmp(params[0], "H") == 0) {
1497: if(num == 3) {
1498: UINT32 l = debugger_get_val(params[1]);
1499: UINT32 r = debugger_get_val(params[2]);
1500: telnet_printf("%08X %08X\n", l + r, l - r);
1501: } else {
1502: telnet_printf("invalid parameter number\n");
1503: }
1504: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) {
1505: break_point_t *break_point_ptr;
1506: #define GET_BREAK_POINT_PTR() { \
1507: if(params[0][0] == 'R') { \
1508: break_point_ptr = &rd_break_point; \
1509: } else if(params[0][0] == 'W') { \
1510: break_point_ptr = &wr_break_point; \
1511: } else if(params[0][0] == 'I') { \
1512: break_point_ptr = &in_break_point; \
1513: } else if(params[0][0] == 'O') { \
1514: break_point_ptr = &out_break_point; \
1515: } else { \
1516: break_point_ptr = &break_point; \
1517: } \
1518: }
1519: GET_BREAK_POINT_PTR();
1520: if(num == 2) {
1521: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1522: UINT32 ofs = debugger_get_ofs(params[1]);
1523: bool found = false;
1524: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1525: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) {
1526: break_point_ptr->table[i].addr = (seg << 4) + ofs;
1527: break_point_ptr->table[i].seg = seg;
1528: break_point_ptr->table[i].ofs = ofs;
1529: break_point_ptr->table[i].status = 1;
1530: found = true;
1531: }
1532: }
1533: if(!found) {
1534: telnet_printf("too many break points\n");
1535: }
1536: } else {
1537: telnet_printf("invalid parameter number\n");
1538: }
1539: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) {
1540: break_point_t *break_point_ptr;
1541: GET_BREAK_POINT_PTR();
1542: if(num == 2) {
1543: UINT32 addr = debugger_get_val(params[1]);
1544: bool found = false;
1545: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1546: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) {
1547: break_point_ptr->table[i].addr = addr;
1548: break_point_ptr->table[i].status = 1;
1549: found = true;
1550: }
1551: }
1552: if(!found) {
1553: telnet_printf("too many break points\n");
1554: }
1555: } else {
1556: telnet_printf("invalid parameter number\n");
1557: }
1558: } 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) {
1559: break_point_t *break_point_ptr;
1560: GET_BREAK_POINT_PTR();
1561: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1562: memset(break_point_ptr, 0, sizeof(break_point_t));
1563: } else if(num >= 2) {
1564: for(int i = 1; i < num; i++) {
1565: int index = debugger_get_val(params[i]);
1566: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1567: telnet_printf("invalid index %x\n", index);
1568: } else {
1569: break_point_ptr->table[index - 1].addr = 0;
1570: break_point_ptr->table[index - 1].seg = 0;
1571: break_point_ptr->table[index - 1].ofs = 0;
1572: break_point_ptr->table[index - 1].status = 0;
1573: }
1574: }
1575: } else {
1576: telnet_printf("invalid parameter number\n");
1577: }
1578: } 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 ||
1579: 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) {
1580: break_point_t *break_point_ptr;
1581: GET_BREAK_POINT_PTR();
1582: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1583: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1584: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1585: if(break_point_ptr->table[i].status != 0) {
1586: break_point_ptr->table[i].status = enabled ? 1 : -1;
1587: }
1588: }
1589: } else if(num >= 2) {
1590: for(int i = 1; i < num; i++) {
1591: int index = debugger_get_val(params[i]);
1592: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1593: telnet_printf("invalid index %x\n", index);
1594: } else if(break_point_ptr->table[index - 1].status == 0) {
1595: telnet_printf("break point %x is null\n", index);
1596: } else {
1597: break_point_ptr->table[index - 1].status = enabled ? 1 : -1;
1598: }
1599: }
1600: } else {
1601: telnet_printf("invalid parameter number\n");
1602: }
1603: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) {
1604: break_point_t *break_point_ptr;
1605: GET_BREAK_POINT_PTR();
1606: if(num == 1) {
1607: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1608: if(break_point_ptr->table[i].status) {
1609: 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);
1610: }
1611: }
1612: } else {
1613: telnet_printf("invalid parameter number\n");
1614: }
1615: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) {
1616: break_point_t *break_point_ptr;
1617: GET_BREAK_POINT_PTR();
1618: if(num == 1) {
1619: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1620: if(break_point_ptr->table[i].status) {
1621: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr);
1622: }
1623: }
1624: } else {
1625: telnet_printf("invalid parameter number\n");
1626: }
1627: } else if(stricmp(params[0], "INTBP") == 0) {
1628: if(num >= 2 && num <= 4) {
1629: int int_num = debugger_get_val(params[1]);
1630: UINT8 ah = 0, ah_registered = 0;
1631: UINT8 al = 0, al_registered = 0;
1632: if(num >= 3) {
1633: ah = debugger_get_val(params[2]);
1634: ah_registered = 1;
1635: }
1636: if(num == 4) {
1637: al = debugger_get_val(params[3]);
1638: al_registered = 1;
1639: }
1640: bool found = false;
1641: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1642: if(int_break_point.table[i].status == 0 || (
1643: int_break_point.table[i].int_num == int_num &&
1644: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered &&
1645: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) {
1646: int_break_point.table[i].int_num = int_num;
1647: int_break_point.table[i].ah = ah;
1648: int_break_point.table[i].ah_registered = ah_registered;
1649: int_break_point.table[i].al = al;
1650: int_break_point.table[i].al_registered = al_registered;
1651: int_break_point.table[i].status = 1;
1652: found = true;
1653: }
1654: }
1655: if(!found) {
1656: telnet_printf("too many break points\n");
1657: }
1658: } else {
1659: telnet_printf("invalid parameter number\n");
1660: }
1661: } else if(stricmp(params[0], "INTBC") == 0) {
1662: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1663: memset(&int_break_point, 0, sizeof(int_break_point_t));
1664: } else if(num >= 2) {
1665: for(int i = 1; i < num; i++) {
1666: int index = debugger_get_val(params[i]);
1667: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1668: telnet_printf("invalid index %x\n", index);
1669: } else {
1670: int_break_point.table[index - 1].int_num = 0;
1671: int_break_point.table[index - 1].ah = 0;
1672: int_break_point.table[index - 1].ah_registered = 0;
1673: int_break_point.table[index - 1].al = 0;
1674: int_break_point.table[index - 1].al_registered = 0;
1675: int_break_point.table[index - 1].status = 0;
1676: }
1677: }
1678: } else {
1679: telnet_printf("invalid parameter number\n");
1680: }
1681: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) {
1682: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1683: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1684: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1685: if(int_break_point.table[i].status != 0) {
1686: int_break_point.table[i].status = enabled ? 1 : -1;
1687: }
1688: }
1689: } else if(num >= 2) {
1690: for(int i = 1; i < num; i++) {
1691: int index = debugger_get_val(params[i]);
1692: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1693: telnet_printf("invalid index %x\n", index);
1694: } else if(int_break_point.table[index - 1].status == 0) {
1695: telnet_printf("break point %x is null\n", index);
1696: } else {
1697: int_break_point.table[index - 1].status = enabled ? 1 : -1;
1698: }
1699: }
1700: } else {
1701: telnet_printf("invalid parameter number\n");
1702: }
1703: } else if(stricmp(params[0], "INTBL") == 0) {
1704: if(num == 1) {
1705: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1706: if(int_break_point.table[i].status) {
1707: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num);
1708: if(int_break_point.table[i].ah_registered) {
1709: telnet_printf(" %02X", int_break_point.table[i].ah);
1710: }
1711: if(int_break_point.table[i].al_registered) {
1712: telnet_printf(" %02X", int_break_point.table[i].al);
1713: }
1714: telnet_printf("\n");
1715: }
1716: }
1717: } else {
1718: telnet_printf("invalid parameter number\n");
1719: }
1720: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) {
1721: if(num == 1 || num == 2) {
1722: break_point_t break_point_stored;
1723: bool break_points_stored = false;
1724:
1725: if(stricmp(params[0], "P") == 0) {
1726: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1727: memset(&break_point, 0, sizeof(break_point_t));
1728: break_points_stored = true;
1729:
1730: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip);
1731: break_point.table[0].status = 1;
1732: } else if(num >= 2) {
1733: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1734: memset(&break_point, 0, sizeof(break_point_t));
1735: break_points_stored = true;
1736:
1737: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1738: UINT32 ofs = debugger_get_ofs(params[1]);
1739: break_point.table[0].addr = (seg << 4) + ofs;
1740: break_point.table[0].seg = seg;
1741: break_point.table[0].ofs = ofs;
1742: break_point.table[0].status = 1;
1743: }
1744: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1745: now_going = true;
1746: now_suspended = false;
1747:
1748: telnet_command("\033[2l"); // key unlock
1749: while(!m_halted && !now_suspended) {
1750: if(telnet_kbhit()) {
1751: break;
1752: }
1753: Sleep(10);
1754: }
1755: now_going = false;
1756: telnet_command("\033[2h"); // key lock
1757:
1758: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1759: Sleep(100);
1760: if(!m_halted && !now_suspended) {
1761: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1762: telnet_printf("waiting until cpu is suspended...\n");
1763: }
1764: }
1765: while(!m_halted && !now_suspended) {
1766: if(telnet_disconnected()) {
1767: break;
1768: }
1769: Sleep(10);
1770: }
1771: dasm_seg = SREG(CS);
1772: dasm_ofs = m_eip;
1773:
1774: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1775: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1776: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1777:
1778: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1779: debugger_regs_info(buffer);
1780: telnet_printf("%s", buffer);
1781:
1782: if(break_point.hit) {
1783: if(stricmp(params[0], "G") == 0 && num == 1) {
1784: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1785: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1786: }
1787: } else if(rd_break_point.hit) {
1788: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1789: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1790: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1791: m_prev_cs, m_prev_eip);
1792: } else if(wr_break_point.hit) {
1793: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1794: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1795: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1796: m_prev_cs, m_prev_eip);
1797: } else if(in_break_point.hit) {
1798: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1799: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1800: in_break_point.table[in_break_point.hit - 1].addr,
1801: m_prev_cs, m_prev_eip);
1802: } else if(out_break_point.hit) {
1803: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1804: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1805: out_break_point.table[out_break_point.hit - 1].addr,
1806: m_prev_cs, m_prev_eip);
1807: } else if(int_break_point.hit) {
1808: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1809: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1810: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1811: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1812: }
1813: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1814: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1815: }
1816: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1817: } else {
1818: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1819: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1820: }
1821: if(break_points_stored) {
1822: memcpy(&break_point, &break_point_stored, sizeof(break_point_t));
1823: }
1824: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1825: debugger_dasm(buffer, SREG(CS), m_eip);
1826: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1827: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1828: } else {
1829: telnet_printf("invalid parameter number\n");
1830: }
1831: } else if(stricmp(params[0], "T") == 0) {
1832: if(num == 1 || num == 2) {
1833: int steps = 1;
1834: if(num >= 2) {
1835: steps = debugger_get_val(params[1]);
1836: }
1837:
1838: telnet_command("\033[2l"); // key unlock
1839: while(steps-- > 0) {
1840: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1841: now_going = false;
1842: now_suspended = false;
1843:
1844: while(!m_halted && !now_suspended) {
1845: if(telnet_disconnected()) {
1846: break;
1847: }
1848: Sleep(10);
1849: }
1850: dasm_seg = SREG(CS);
1851: dasm_ofs = m_eip;
1852:
1853: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1854: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1855: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1856:
1857: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1858: debugger_regs_info(buffer);
1859: telnet_printf("%s", buffer);
1860:
1861: 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()) {
1862: break;
1863: }
1864: }
1865: telnet_command("\033[2h"); // key lock
1866:
1867: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1868: Sleep(100);
1869: if(!m_halted && !now_suspended) {
1870: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1871: telnet_printf("waiting until cpu is suspended...\n");
1872: }
1873: }
1874: while(!m_halted && !now_suspended) {
1875: if(telnet_disconnected()) {
1876: break;
1877: }
1878: Sleep(10);
1879: }
1880: if(break_point.hit) {
1881: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1882: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1883: } else if(rd_break_point.hit) {
1884: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1885: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1886: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1887: m_prev_cs, m_prev_eip);
1888: } else if(wr_break_point.hit) {
1889: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1890: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1891: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1892: m_prev_cs, m_prev_eip);
1893: } else if(in_break_point.hit) {
1894: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1895: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1896: in_break_point.table[in_break_point.hit - 1].addr,
1897: m_prev_cs, m_prev_eip);
1898: } else if(out_break_point.hit) {
1899: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1900: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1901: out_break_point.table[out_break_point.hit - 1].addr,
1902: m_prev_cs, m_prev_eip);
1903: } else if(int_break_point.hit) {
1904: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1905: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1906: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1907: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1908: }
1909: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1910: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1911: }
1912: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1913: } else if(steps > 0) {
1914: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1915: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1916: }
1917: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1918: debugger_dasm(buffer, SREG(CS), m_eip);
1919: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1920: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1921: } else {
1922: telnet_printf("invalid parameter number\n");
1923: }
1924: } else if(stricmp(params[0], "Q") == 0) {
1925: break;
1926: } else if(stricmp(params[0], "X") == 0) {
1927: debugger_process_info(buffer);
1928: telnet_printf("%s", buffer);
1929: } else if(stricmp(params[0], ">") == 0) {
1930: if(num == 2) {
1931: if(fp_debugger != NULL) {
1932: fclose(fp_debugger);
1933: fp_debugger = NULL;
1934: }
1935: fp_debugger = fopen(params[1], "w");
1936: } else {
1937: telnet_printf("invalid parameter number\n");
1938: }
1939: } else if(stricmp(params[0], "<") == 0) {
1940: if(num == 2) {
1941: if(fi_debugger != NULL) {
1942: fclose(fi_debugger);
1943: fi_debugger = NULL;
1944: }
1945: fi_debugger = fopen(params[1], "r");
1946: } else {
1947: telnet_printf("invalid parameter number\n");
1948: }
1949: } else if(stricmp(params[0], "?") == 0) {
1950: telnet_printf("D [<start> [<end>]] - dump memory\n");
1951: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n");
1952: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n");
1953: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n");
1954: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n");
1955:
1956: telnet_printf("R - show registers\n");
1957: telnet_printf("R <reg> <value> - edit register\n");
1958: telnet_printf("S <start> <end> <list> - search\n");
1959: telnet_printf("U [<start> [<end>]] - unassemble\n");
1960:
1961: telnet_printf("H <value> <value> - hexadd\n");
1962:
1963: telnet_printf("BP <address> - set breakpoint\n");
1964: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n");
1965: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n");
1966: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n");
1967: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n");
1968: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n");
1969:
1970: telnet_printf("G - go (press enter key to break)\n");
1971: telnet_printf("G <address> - go and break at address\n");
1972: telnet_printf("P - trace one opcode (step over)\n");
1973: telnet_printf("T [<count>] - trace (step in)\n");
1974: telnet_printf("Q - quit\n");
1975: telnet_printf("X - show dos process info\n");
1976:
1977: telnet_printf("> <filename> - output logfile\n");
1978: telnet_printf("< <filename> - input commands from file\n");
1979:
1980: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n");
1981: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n");
1982: } else {
1983: telnet_printf("unknown command %s\n", params[0]);
1984: }
1985: }
1986: }
1987: if(fp_debugger != NULL) {
1988: fclose(fp_debugger);
1989: fp_debugger = NULL;
1990: }
1991: if(fi_debugger != NULL) {
1992: fclose(fi_debugger);
1993: fi_debugger = NULL;
1994: }
1995: now_debugging = now_going = now_suspended = force_suspend = false;
1996: closesocket(cli_socket);
1997: }
1998:
1999: const char *debugger_get_ttermpro_path()
2000: {
2001: static char path[MAX_PATH] = {0};
2002:
2003: if(getenv("ProgramFiles")) {
2004: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles"));
2005: }
2006: return(path);
2007: }
2008:
2009: const char *debugger_get_ttermpro_x86_path()
2010: {
2011: static char path[MAX_PATH] = {0};
2012:
2013: if(getenv("ProgramFiles(x86)")) {
2014: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)"));
2015: }
2016: return(path);
2017: }
2018:
2019: const char *debugger_get_putty_path()
2020: {
2021: static char path[MAX_PATH] = {0};
2022:
2023: if(getenv("ProgramFiles")) {
2024: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles"));
2025: }
2026: return(path);
2027: }
2028:
2029: const char *debugger_get_putty_x86_path()
2030: {
2031: static char path[MAX_PATH] = {0};
2032:
2033: if(getenv("ProgramFiles(x86)")) {
2034: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)"));
2035: }
2036: return(path);
2037: }
2038:
2039: const char *debugger_get_telnet_path()
2040: {
2041: // NOTE: When you run 32bit version of msdos.exe on Windows x64,
2042: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64.
2043: // But 32bit version of telnet.exe will not be installed in SysWOW64
2044: // and 64bit version of telnet.exe will be installed in System32.
2045: static char path[MAX_PATH] = {0};
2046:
2047: if(getenv("windir") != NULL) {
2048: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir"));
2049: }
2050: return(path);
2051: }
2052:
2053: DWORD WINAPI debugger_thread(LPVOID)
2054: {
2055: WSADATA was_data;
2056: struct sockaddr_in svr_addr;
2057: struct sockaddr_in cli_addr;
2058: int cli_addr_len = sizeof(cli_addr);
2059: int port = 23;
2060: int bind_stat = SOCKET_ERROR;
2061: struct timeval timeout;
2062:
2063: WSAStartup(MAKEWORD(2,0), &was_data);
2064:
2065: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
2066: memset(&svr_addr, 0, sizeof(svr_addr));
2067: svr_addr.sin_family = AF_INET;
2068: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
2069:
2070: while(!m_halted && port < 10000) {
2071: svr_addr.sin_port = htons(port);
2072: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
2073: break;
2074: } else {
2075: port = (port == 23) ? 9000 : (port + 1);
2076: }
2077: }
2078: if(bind_stat == 0) {
2079: timeout.tv_sec = 1;
2080: timeout.tv_usec = 0;
2081: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
2082:
2083: listen(svr_socket, 1);
2084:
2085: char command[MAX_PATH] = {0};
2086: STARTUPINFO si;
2087: PROCESS_INFORMATION pi;
2088:
2089: if(_access(debugger_get_ttermpro_path(), 0) == 0) {
2090: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port);
2091: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) {
2092: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port);
2093: } else if(_access(debugger_get_putty_path(), 0) == 0) {
2094: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port);
2095: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) {
2096: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port);
2097: } else if(_access(debugger_get_telnet_path(), 0) == 0) {
2098: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port);
2099: }
2100: if(command[0] != '\0') {
2101: memset(&si, 0, sizeof(STARTUPINFO));
2102: memset(&pi, 0, sizeof(PROCESS_INFORMATION));
2103: CreateProcess(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
2104: }
2105:
2106: while(!m_halted) {
2107: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
2108: u_long val = 1;
2109: ioctlsocket(cli_socket, FIONBIO, &val);
2110: debugger_main();
2111: }
2112: }
2113: }
2114: }
2115: WSACleanup();
2116: return(0);
2117: }
2118: #endif
2119:
2120: /* ----------------------------------------------------------------------------
1.1 root 2121: main
2122: ---------------------------------------------------------------------------- */
2123:
1.1.1.28 root 2124: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
2125: {
2126: if(dwCtrlType == CTRL_BREAK_EVENT) {
1.1.1.33 root 2127: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 2128: #ifdef USE_SERVICE_THREAD
! 2129: EnterCriticalSection(&key_buf_crit_sect);
! 2130: #endif
1.1.1.33 root 2131: key_buf_char->clear();
2132: key_buf_scan->clear();
1.1.1.35! root 2133: #ifdef USE_SERVICE_THREAD
! 2134: LeaveCriticalSection(&key_buf_crit_sect);
! 2135: #endif
1.1.1.33 root 2136: }
2137: // key_code = key_recv = 0;
1.1.1.28 root 2138: return TRUE;
2139: } else if(dwCtrlType == CTRL_C_EVENT) {
2140: return TRUE;
2141: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
2142: // this program will be terminated abnormally, do minimum end process
2143: exit_handler();
2144: exit(1);
2145: }
2146: return FALSE;
2147: }
2148:
2149: void exit_handler()
2150: {
2151: if(temp_file_created) {
2152: DeleteFile(temp_file_path);
2153: temp_file_created = false;
2154: }
2155: if(key_buf_char != NULL) {
2156: key_buf_char->release();
2157: delete key_buf_char;
2158: key_buf_char = NULL;
2159: }
2160: if(key_buf_scan != NULL) {
2161: key_buf_scan->release();
2162: delete key_buf_scan;
2163: key_buf_scan = NULL;
2164: }
1.1.1.32 root 2165: #ifdef SUPPORT_XMS
2166: msdos_xms_release();
2167: #endif
1.1.1.28 root 2168: hardware_release();
2169: }
2170:
1.1.1.35! root 2171: #ifdef USE_VRAM_THREAD
1.1.1.28 root 2172: DWORD WINAPI vram_thread(LPVOID)
2173: {
2174: while(!m_halted) {
2175: EnterCriticalSection(&vram_crit_sect);
2176: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
2177: vram_flush_char();
2178: }
2179: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
2180: vram_flush_attr();
2181: }
2182: vram_last_length_char = vram_length_char;
2183: vram_last_length_attr = vram_length_attr;
2184: LeaveCriticalSection(&vram_crit_sect);
2185: // this is about half the maximum keyboard repeat rate - any
2186: // lower tends to be jerky, any higher misses updates
2187: Sleep(15);
2188: }
2189: return 0;
2190: }
2191: #endif
2192:
2193: long get_section_in_exec_file(FILE *fp, char *name)
2194: {
2195: UINT8 header[0x400];
2196:
2197: long position = ftell(fp);
2198: fseek(fp, 0, SEEK_SET);
2199: fread(header, sizeof(header), 1, fp);
2200: fseek(fp, position, SEEK_SET);
2201:
2202: try {
2203: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2204: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2205: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2206: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2207: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2208: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2209:
2210: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
2211: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
2212: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
2213: return(sectionHeader->PointerToRawData);
2214: }
2215: }
2216: } catch(...) {
2217: }
2218: return(0);
2219: }
2220:
1.1.1.10 root 2221: bool is_started_from_command_prompt()
2222: {
1.1.1.18 root 2223: bool ret = false;
2224:
2225: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
2226: if(hLibrary) {
2227: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
2228: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
2229: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
2230: if(lpfnGetConsoleProcessList) {
2231: DWORD pl;
2232: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
2233: FreeLibrary(hLibrary);
2234: return(ret);
2235: }
2236: FreeLibrary(hLibrary);
2237: }
2238:
2239: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2240: if(hSnapshot != INVALID_HANDLE_VALUE) {
2241: DWORD dwParentProcessID = 0;
2242: PROCESSENTRY32 pe32;
2243: pe32.dwSize = sizeof(PROCESSENTRY32);
2244: if(Process32First(hSnapshot, &pe32)) {
2245: do {
2246: if(pe32.th32ProcessID == GetCurrentProcessId()) {
2247: dwParentProcessID = pe32.th32ParentProcessID;
2248: break;
2249: }
2250: } while(Process32Next(hSnapshot, &pe32));
2251: }
2252: CloseHandle(hSnapshot);
2253: if(dwParentProcessID != 0) {
2254: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
2255: if(hProcess != NULL) {
2256: HMODULE hMod;
2257: DWORD cbNeeded;
2258: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
2259: char module_name[MAX_PATH];
2260: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
2261: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
2262: }
2263: }
2264: CloseHandle(hProcess);
2265: }
2266: }
2267: }
2268: return(ret);
1.1.1.14 root 2269: }
2270:
2271: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
2272: {
1.1.1.24 root 2273: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 2274: OSVERSIONINFOEX osvi;
2275: DWORDLONG dwlConditionMask = 0;
2276: int op = VER_GREATER_EQUAL;
2277:
2278: // Initialize the OSVERSIONINFOEX structure.
2279: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
2280: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
2281: osvi.dwMajorVersion = dwMajorVersion;
2282: osvi.dwMinorVersion = dwMinorVersion;
2283: osvi.wServicePackMajor = wServicePackMajor;
2284: osvi.wServicePackMinor = wServicePackMinor;
2285:
2286: // Initialize the condition mask.
2287: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
2288: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
2289: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
2290: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
2291:
2292: // Perform the test.
2293: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
2294: }
2295:
1.1.1.27 root 2296: void get_sio_port_numbers()
2297: {
2298: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
2299: HDEVINFO hDevInfo = 0;
2300: HKEY hKey = 0;
2301: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
2302: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
2303: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
2304: char chData[256];
2305: DWORD dwType = 0;
2306: DWORD dwSize = sizeof(chData);
2307: int port_number = 0;
2308:
2309: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
2310: if(_strnicmp(chData, "COM", 3) == 0) {
2311: port_number = atoi(chData + 3);
2312: }
2313: }
2314: RegCloseKey(hKey);
2315:
1.1.1.29 root 2316: 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 2317: continue;
2318: }
2319: if(sio_port_number[0] == 0) {
2320: sio_port_number[0] = port_number;
2321: } else if(sio_port_number[1] == 0) {
2322: sio_port_number[1] = port_number;
1.1.1.29 root 2323: } else if(sio_port_number[2] == 0) {
2324: sio_port_number[2] = port_number;
2325: } else if(sio_port_number[3] == 0) {
2326: sio_port_number[3] = port_number;
1.1.1.27 root 2327: }
1.1.1.29 root 2328: 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 2329: break;
2330: }
2331: }
2332: }
2333: }
2334: }
2335:
1.1.1.28 root 2336: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
2337:
1.1 root 2338: int main(int argc, char *argv[], char *envp[])
2339: {
1.1.1.9 root 2340: int arg_offset = 0;
2341: int standard_env = 0;
1.1.1.14 root 2342: int buf_width = 0, buf_height = 0;
1.1.1.28 root 2343: bool get_console_info_success = false;
2344: bool screen_size_changed = false;
2345:
2346: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
2347: GetModuleFileName(NULL, path, MAX_PATH);
2348: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 2349:
1.1.1.27 root 2350: char dummy_argv_0[] = "msdos.exe";
2351: char dummy_argv_1[MAX_PATH];
2352: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
2353: char new_exec_file[MAX_PATH];
2354: bool convert_cmd_file = false;
1.1.1.28 root 2355: unsigned int code_page = 0;
1.1.1.27 root 2356:
2357: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 2358: // check if command file is embedded to this execution file
2359: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 2360: FILE* fp = fopen(full, "rb");
1.1.1.28 root 2361: long offset = get_section_in_exec_file(fp, ".msdos");
2362: if(offset != 0) {
1.1.1.30 root 2363: UINT8 buffer[16];
1.1.1.28 root 2364: fseek(fp, offset, SEEK_SET);
2365: fread(buffer, sizeof(buffer), 1, fp);
2366:
2367: // restore flags
2368: stay_busy = ((buffer[0] & 0x01) != 0);
2369: no_windows = ((buffer[0] & 0x02) != 0);
2370: standard_env = ((buffer[0] & 0x04) != 0);
2371: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
2372: limit_max_memory = ((buffer[0] & 0x10) != 0);
2373: if((buffer[0] & 0x20) != 0) {
2374: get_sio_port_numbers();
2375: }
2376: if((buffer[0] & 0x40) != 0) {
2377: UMB_TOP = EMS_TOP + EMS_SIZE;
2378: support_ems = true;
1.1.1.30 root 2379: }
1.1.1.27 root 2380: #ifdef SUPPORT_XMS
1.1.1.30 root 2381: if((buffer[0] & 0x80) != 0) {
1.1.1.28 root 2382: support_xms = true;
2383: }
1.1.1.30 root 2384: #endif
1.1.1.28 root 2385: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
2386: buf_width = buffer[1] | (buffer[2] << 8);
2387: buf_height = buffer[3] | (buffer[4] << 8);
2388: }
2389: if(buffer[5] != 0) {
1.1.1.30 root 2390: dos_major_version = buffer[5];
2391: dos_minor_version = buffer[6];
2392: }
2393: if(buffer[7] != 0) {
2394: win_major_version = buffer[7];
2395: win_minor_version = buffer[8];
1.1.1.28 root 2396: }
1.1.1.30 root 2397: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
1.1.1.28 root 2398: SetConsoleCP(code_page);
2399: SetConsoleOutputCP(code_page);
2400: }
1.1.1.30 root 2401: int name_len = buffer[11];
2402: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
1.1.1.28 root 2403:
2404: // restore command file name
2405: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
2406: fread(dummy_argv_1, name_len, 1, fp);
2407:
2408: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
2409: // if original command file exists, create a temporary file name
2410: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
2411: // create a temporary command file in the current director
2412: DeleteFile(dummy_argv_1);
1.1.1.27 root 2413: } else {
1.1.1.28 root 2414: // create a temporary command file in the temporary folder
2415: GetTempPath(MAX_PATH, path);
2416: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
2417: DeleteFile(dummy_argv_1);
2418: } else {
2419: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
2420: }
1.1.1.27 root 2421: }
1.1.1.28 root 2422: // check the command file type
2423: fread(buffer, 2, 1, fp);
2424: fseek(fp, -2, SEEK_CUR);
2425: if(memcmp(buffer, "MZ", 2) != 0) {
2426: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
2427: } else {
2428: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 2429: }
2430: }
1.1.1.28 root 2431:
2432: // restore command file
2433: FILE* fo = fopen(dummy_argv_1, "wb");
2434: for(int i = 0; i < file_len; i++) {
2435: fputc(fgetc(fp), fo);
2436: }
2437: fclose(fo);
2438:
2439: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
2440: temp_file_created = true;
2441: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
2442:
2443: // adjust argc/argv
2444: for(int i = 1; i < argc && (i + 1) < 256; i++) {
2445: dummy_argv[i + 1] = argv[i];
2446: }
2447: argc++;
2448: argv = dummy_argv;
1.1.1.27 root 2449: }
2450: fclose(fp);
2451: }
1.1.1.9 root 2452: for(int i = 1; i < argc; i++) {
1.1.1.25 root 2453: if(_strnicmp(argv[i], "-b", 2) == 0) {
2454: stay_busy = true;
2455: arg_offset++;
1.1.1.27 root 2456: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
2457: if(argv[i][2] != '\0') {
2458: strcpy(new_exec_file, &argv[i][2]);
2459: } else {
2460: strcpy(new_exec_file, "new_exec_file.exe");
2461: }
2462: convert_cmd_file = true;
2463: arg_offset++;
1.1.1.28 root 2464: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
2465: if(IS_NUMERIC(argv[i][2])) {
2466: code_page = atoi(&argv[i][2]);
2467: } else {
2468: code_page = GetConsoleCP();
2469: }
2470: arg_offset++;
1.1.1.25 root 2471: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
2472: no_windows = true;
2473: arg_offset++;
2474: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 2475: standard_env = 1;
2476: arg_offset++;
1.1.1.14 root 2477: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
2478: ignore_illegal_insn = true;
2479: arg_offset++;
2480: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
2481: limit_max_memory = true;
2482: arg_offset++;
2483: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 2484: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
2485: buf_width = buf_height = 0;
2486: }
2487: if(buf_width <= 0 || buf_width > 0x7fff) {
2488: buf_width = 80;
2489: }
2490: if(buf_height <= 0 || buf_height > 0x7fff) {
2491: buf_height = 25;
2492: }
1.1.1.14 root 2493: arg_offset++;
1.1.1.25 root 2494: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 2495: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29 root 2496: char *p0 = &argv[i][2], *p1, *p2, *p3;
2497: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
2498: sio_port_number[1] = atoi(p1 + 1);
2499: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
2500: sio_port_number[2] = atoi(p2 + 1);
2501: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
2502: sio_port_number[3] = atoi(p3 + 1);
2503: }
2504: }
1.1.1.25 root 2505: }
1.1.1.29 root 2506: sio_port_number[0] = atoi(p0);
1.1.1.25 root 2507: }
1.1.1.29 root 2508: 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 2509: get_sio_port_numbers();
1.1.1.25 root 2510: }
2511: arg_offset++;
1.1.1.9 root 2512: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 2513: 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 2514: dos_major_version = argv[i][2] - '0';
2515: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2516: }
2517: arg_offset++;
2518: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
2519: 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]))) {
2520: win_major_version = argv[i][2] - '0';
2521: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 2522: }
2523: arg_offset++;
1.1.1.25 root 2524: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
2525: UMB_TOP = EMS_TOP + EMS_SIZE;
2526: support_ems = true;
2527: #ifdef SUPPORT_XMS
2528: support_xms = true;
2529: #endif
2530: arg_offset++;
1.1.1.9 root 2531: } else {
2532: break;
2533: }
2534: }
2535: if(argc < 2 + arg_offset) {
1.1 root 2536: #ifdef _WIN64
1.1.1.14 root 2537: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 2538: #else
1.1.1.14 root 2539: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 2540: #endif
1.1.1.25 root 2541: fprintf(stderr,
1.1.1.28 root 2542: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.30 root 2543: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
1.1.1.25 root 2544: "\n"
2545: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 2546: #ifdef _WIN64
1.1.1.27 root 2547: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 2548: #else
1.1.1.27 root 2549: "\t-c\tconvert command file to 32bit execution file\n"
2550: #endif
1.1.1.28 root 2551: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 2552: "\t-d\tpretend running under straight DOS, not Windows\n"
2553: "\t-e\tuse a reduced environment block\n"
2554: "\t-i\tignore invalid instructions\n"
2555: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
2556: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
2557: "\t-s\tenable serial I/O and set host's COM port numbers\n"
2558: "\t-v\tset the DOS version\n"
1.1.1.30 root 2559: "\t-w\tset the Windows version\n"
1.1.1.19 root 2560: #ifdef SUPPORT_XMS
1.1.1.28 root 2561: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 2562: #else
1.1.1.28 root 2563: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 2564: #endif
2565: );
1.1.1.10 root 2566:
2567: if(!is_started_from_command_prompt()) {
2568: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
2569: while(!_kbhit()) {
2570: Sleep(10);
2571: }
2572: }
1.1.1.20 root 2573: #ifdef _DEBUG
2574: _CrtDumpMemoryLeaks();
2575: #endif
1.1 root 2576: return(EXIT_FAILURE);
2577: }
1.1.1.27 root 2578: if(convert_cmd_file) {
2579: retval = EXIT_FAILURE;
1.1.1.28 root 2580: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 2581: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 2582: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 2583:
1.1.1.28 root 2584: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
2585: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
2586: } else if((fp = fopen(full, "rb")) == NULL) {
2587: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 2588: } else {
1.1.1.28 root 2589: long offset = get_section_in_exec_file(fp, ".msdos");
2590: if(offset != 0) {
2591: UINT8 buffer[14];
2592: fseek(fp, offset, SEEK_SET);
2593: fread(buffer, sizeof(buffer), 1, fp);
2594: memset(path, 0, sizeof(path));
2595: fread(path, buffer[9], 1, fp);
2596: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
2597: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
2598: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
2599: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
2600: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
2601: } else {
2602: // read pe header of msdos.exe
2603: UINT8 header[0x400];
2604: fseek(fp, 0, SEEK_SET);
2605: fread(header, sizeof(header), 1, fp);
2606:
2607: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2608: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2609: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2610: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2611: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2612: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
2613: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2614:
2615: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
2616: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
2617: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
2618: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
2619: if(dwExtraLastSectionBytes != 0) {
2620: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
2621: dwLastSectionSize += dwRemain;
2622: }
2623: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
2624:
2625: // store msdos.exe
2626: fseek(fp, 0, SEEK_SET);
2627: for(int i = 0; i < dwEndOfFile; i++) {
2628: if((data = fgetc(fp)) != EOF) {
2629: fputc(data, fo);
2630: } else {
2631: // we should not reach here :-(
2632: fputc(0, fo);
2633: }
2634: }
2635:
2636: // store options
2637: UINT8 flags = 0;
2638: if(stay_busy) {
2639: flags |= 0x01;
2640: }
2641: if(no_windows) {
2642: flags |= 0x02;
2643: }
2644: if(standard_env) {
2645: flags |= 0x04;
2646: }
2647: if(ignore_illegal_insn) {
2648: flags |= 0x08;
2649: }
2650: if(limit_max_memory) {
2651: flags |= 0x10;
2652: }
1.1.1.29 root 2653: 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 2654: flags |= 0x20;
2655: }
2656: if(support_ems) {
2657: flags |= 0x40;
2658: }
1.1.1.30 root 2659: #ifdef SUPPORT_XMS
2660: if(support_xms) {
2661: flags |= 0x80;
2662: }
2663: #endif
1.1.1.28 root 2664:
2665: fputc(flags, fo);
2666: fputc((buf_width >> 0) & 0xff, fo);
2667: fputc((buf_width >> 8) & 0xff, fo);
2668: fputc((buf_height >> 0) & 0xff, fo);
2669: fputc((buf_height >> 8) & 0xff, fo);
1.1.1.30 root 2670: fputc(dos_major_version, fo);
2671: fputc(dos_minor_version, fo);
2672: fputc(win_major_version, fo);
2673: fputc(win_minor_version, fo);
1.1.1.28 root 2674: fputc((code_page >> 0) & 0xff, fo);
2675: fputc((code_page >> 8) & 0xff, fo);
2676:
2677: // store command file info
2678: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
2679: int name_len = strlen(name);
2680: fseek(fs, 0, SEEK_END);
2681: long file_size = ftell(fs);
2682:
2683: fputc(name_len, fo);
2684: fputc((file_size >> 0) & 0xff, fo);
2685: fputc((file_size >> 8) & 0xff, fo);
2686: fputc((file_size >> 16) & 0xff, fo);
2687: fputc((file_size >> 24) & 0xff, fo);
2688: fwrite(name, name_len, 1, fo);
2689:
2690: // store command file
2691: fseek(fs, 0, SEEK_SET);
2692: for(int i = 0; i < file_size; i++) {
2693: if((data = fgetc(fs)) != EOF) {
2694: fputc(data, fo);
2695: } else {
2696: // we should not reach here :-(
2697: fputc(0, fo);
2698: }
2699: }
2700:
2701: // store padding data and update pe header
1.1.1.29 root 2702: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
2703: coffHeader->NumberOfSections++;
2704: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
2705: memcpy(newSectionHeader->Name, ".msdos", 6);
2706: newSectionHeader->VirtualAddress = dwVirtualAddress;
2707: newSectionHeader->PointerToRawData = dwEndOfFile;
2708: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 2709: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
2710: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
2711: if(dwExtraRawBytes != 0) {
1.1.1.29 root 2712: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 2713: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
2714: for(int i = 0; i < dwRemain; i++) {
1.1.1.29 root 2715: if(i < 2) {
2716: fputc(padding[i & 15], fo);
2717: } else {
2718: fputc(padding[(i - 2) & 15], fo);
2719: }
1.1.1.28 root 2720: }
2721: newSectionHeader->SizeOfRawData += dwRemain;
2722: }
2723: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
2724:
2725: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
2726: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
2727: if(dwExtraNewSectionBytes != 0) {
2728: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
2729: dwNewSectionSize += dwRemain;
2730: }
2731: optionalHeader->SizeOfImage += dwNewSectionSize;
2732:
2733: fseek(fo, 0, SEEK_SET);
2734: fwrite(header, sizeof(header), 1, fo);
2735:
2736: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
2737: retval = EXIT_SUCCESS;
1.1.1.27 root 2738: }
2739: }
2740: if(fp != NULL) {
2741: fclose(fp);
2742: }
2743: if(fs != NULL) {
2744: fclose(fs);
2745: }
2746: if(fo != NULL) {
2747: fclose(fo);
2748: }
2749: }
2750: #ifdef _DEBUG
2751: _CrtDumpMemoryLeaks();
2752: #endif
2753: return(retval);
2754: }
1.1 root 2755:
1.1.1.14 root 2756: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
2757:
1.1.1.23 root 2758: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2759: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 2760: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 2761:
1.1.1.28 root 2762: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 2763: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 2764: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 2765:
1.1.1.14 root 2766: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
2767: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
2768: SCR_BUF(y,x).Char.AsciiChar = ' ';
2769: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 2770: }
2771: }
1.1.1.28 root 2772: if(get_console_info_success) {
1.1.1.12 root 2773: scr_width = csbi.dwSize.X;
1.1.1.14 root 2774: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2775:
1.1.1.28 root 2776: // v-text shadow buffer size must be lesser than 0x7fd0
2777: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 2778: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
2779: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
2780: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 2781: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 2782: scr_width = 80;
2783: scr_height = 25;
2784: }
1.1.1.28 root 2785: screen_size_changed = true;
1.1.1.14 root 2786: }
1.1.1.12 root 2787: } else {
2788: // for a proof (not a console)
2789: scr_width = 80;
2790: scr_height = 25;
2791: }
1.1.1.14 root 2792: scr_buf_size.X = scr_width;
2793: scr_buf_size.Y = scr_height;
2794: scr_buf_pos.X = scr_buf_pos.Y = 0;
2795: scr_top = csbi.srWindow.Top;
1.1 root 2796: cursor_moved = false;
2797:
1.1.1.35! root 2798: #ifdef USE_SERVICE_THREAD
! 2799: InitializeCriticalSection(&input_crit_sect);
! 2800: InitializeCriticalSection(&key_buf_crit_sect);
! 2801: InitializeCriticalSection(&putch_crit_sect);
! 2802: #endif
1.1.1.25 root 2803: key_buf_char = new FIFO(256);
2804: key_buf_scan = new FIFO(256);
1.1 root 2805:
2806: hardware_init();
2807:
1.1.1.33 root 2808: #ifdef USE_DEBUGGER
2809: debugger_init();
2810: #endif
2811:
1.1.1.9 root 2812: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 2813: retval = EXIT_FAILURE;
2814: } else {
1.1.1.27 root 2815: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 2816: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
2817: #endif
2818: SetConsoleCtrlHandler(ctrl_handler, TRUE);
2819:
1.1.1.28 root 2820: if(screen_size_changed) {
1.1.1.24 root 2821: change_console_size(scr_width, scr_height);
2822: }
1.1.1.8 root 2823: TIMECAPS caps;
2824: timeGetDevCaps(&caps, sizeof(TIMECAPS));
2825: timeBeginPeriod(caps.wPeriodMin);
1.1.1.35! root 2826: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2827: InitializeCriticalSection(&vram_crit_sect);
2828: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
2829: #endif
1.1.1.33 root 2830: #ifdef USE_DEBUGGER
2831: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL));
2832: // wait until telnet client starts and connects to me
2833: if(_access(debugger_get_ttermpro_path(), 0) == 0 ||
2834: _access(debugger_get_ttermpro_x86_path(), 0) == 0 ||
2835: _access(debugger_get_putty_path(), 0) == 0 ||
2836: _access(debugger_get_putty_x86_path(), 0) == 0 ||
2837: _access(debugger_get_telnet_path(), 0) == 0) {
2838: for(int i = 0; i < 100 && cli_socket == 0; i++) {
2839: Sleep(100);
2840: }
2841: }
2842: #endif
1.1 root 2843: hardware_run();
1.1.1.35! root 2844: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2845: vram_flush();
2846: DeleteCriticalSection(&vram_crit_sect);
2847: #endif
1.1.1.24 root 2848: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 2849:
1.1.1.24 root 2850: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 2851: if(get_console_info_success) {
1.1.1.23 root 2852: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2853: if(restore_console_on_exit) {
1.1.1.14 root 2854: // window can't be bigger than buffer,
2855: // buffer can't be smaller than window,
2856: // so make a tiny window,
2857: // set the required buffer,
2858: // then set the required window
2859: SMALL_RECT rect;
2860: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
2861: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 2862: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 2863: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 2864: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2865: }
1.1.1.14 root 2866: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
2867: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 2868: }
1.1.1.24 root 2869: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
2870:
1.1 root 2871: msdos_finish();
1.1.1.14 root 2872:
2873: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 2874: }
1.1.1.35! root 2875: if(temp_file_created) {
! 2876: DeleteFile(temp_file_path);
! 2877: temp_file_created = false;
! 2878: }
1.1.1.10 root 2879: hardware_finish();
2880:
1.1.1.28 root 2881: if(key_buf_char != NULL) {
2882: key_buf_char->release();
2883: delete key_buf_char;
2884: key_buf_char = NULL;
2885: }
2886: if(key_buf_scan != NULL) {
2887: key_buf_scan->release();
2888: delete key_buf_scan;
2889: key_buf_scan = NULL;
2890: }
1.1.1.35! root 2891: #ifdef USE_SERVICE_THREAD
! 2892: DeleteCriticalSection(&input_crit_sect);
! 2893: DeleteCriticalSection(&key_buf_crit_sect);
! 2894: DeleteCriticalSection(&putch_crit_sect);
! 2895: #endif
1.1.1.20 root 2896: #ifdef _DEBUG
2897: _CrtDumpMemoryLeaks();
2898: #endif
1.1 root 2899: return(retval);
2900: }
2901:
1.1.1.20 root 2902: /* ----------------------------------------------------------------------------
2903: console
2904: ---------------------------------------------------------------------------- */
2905:
1.1.1.14 root 2906: void change_console_size(int width, int height)
1.1.1.12 root 2907: {
1.1.1.23 root 2908: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2909: CONSOLE_SCREEN_BUFFER_INFO csbi;
2910: SMALL_RECT rect;
2911: COORD co;
2912:
2913: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 2914: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
2915: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
2916: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
2917: SET_RECT(rect, 0, 0, width - 1, height - 1);
2918: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2919: } else if(csbi.dwCursorPosition.Y > height - 1) {
2920: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
2921: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2922: SET_RECT(rect, 0, 0, width - 1, height - 1);
2923: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 2924: }
2925: }
1.1.1.14 root 2926: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 2927: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 2928: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 2929: SetConsoleCursorPosition(hStdout, co);
2930: cursor_moved = true;
2931: }
1.1.1.14 root 2932:
2933: // window can't be bigger than buffer,
2934: // buffer can't be smaller than window,
2935: // so make a tiny window,
2936: // set the required buffer,
2937: // then set the required window
2938: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 2939: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 2940: co.X = width;
2941: co.Y = height;
1.1.1.12 root 2942: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 2943: SET_RECT(rect, 0, 0, width - 1, height - 1);
2944: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2945:
2946: scr_width = scr_buf_size.X = width;
2947: scr_height = scr_buf_size.Y = height;
2948: scr_top = 0;
2949:
2950: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2951:
2952: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 2953: text_vram_end_address = text_vram_top_address + regen;
2954: shadow_buffer_end_address = shadow_buffer_top_address + regen;
2955:
1.1.1.14 root 2956: if(regen > 0x4000) {
2957: regen = 0x8000;
2958: vram_pages = 1;
2959: } else if(regen > 0x2000) {
2960: regen = 0x4000;
2961: vram_pages = 2;
2962: } else if(regen > 0x1000) {
2963: regen = 0x2000;
2964: vram_pages = 4;
2965: } else {
2966: regen = 0x1000;
2967: vram_pages = 8;
2968: }
1.1.1.15 root 2969: *(UINT16 *)(mem + 0x44a) = scr_width;
2970: *(UINT16 *)(mem + 0x44c) = regen;
2971: *(UINT8 *)(mem + 0x484) = scr_height - 1;
2972:
1.1.1.24 root 2973: mouse.min_position.x = 0;
2974: mouse.min_position.y = 0;
1.1.1.34 root 2975: mouse.max_position.x = 8 * (scr_width - 1);
2976: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 2977:
1.1.1.15 root 2978: restore_console_on_exit = true;
1.1.1.14 root 2979: }
2980:
2981: void clear_scr_buffer(WORD attr)
2982: {
2983: for(int y = 0; y < scr_height; y++) {
2984: for(int x = 0; x < scr_width; x++) {
2985: SCR_BUF(y,x).Char.AsciiChar = ' ';
2986: SCR_BUF(y,x).Attributes = attr;
2987: }
2988: }
1.1.1.12 root 2989: }
2990:
1.1.1.24 root 2991: bool update_console_input()
1.1 root 2992: {
1.1.1.35! root 2993: #ifdef USE_SERVICE_THREAD
! 2994: EnterCriticalSection(&input_crit_sect);
! 2995: #endif
1.1.1.23 root 2996: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 2997: DWORD dwNumberOfEvents = 0;
1.1 root 2998: DWORD dwRead;
2999: INPUT_RECORD ir[16];
1.1.1.24 root 3000: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
3001: bool result = false;
1.1 root 3002:
1.1.1.8 root 3003: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
3004: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
3005: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 3006: if(ir[i].EventType & MOUSE_EVENT) {
1.1.1.34 root 3007: if(mouse.hidden == 0) {
3008: // NOTE: if restore_console_on_exit, console is not scrolled
3009: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
3010: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
3011: }
3012: // FIXME: character size is always 8x8 ???
3013: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
3014: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
3015:
3016: if(mouse.position.x != x || mouse.position.y != y) {
3017: mouse.position.x = x;
3018: mouse.position.y = y;
3019: mouse.status |= 1;
3020: }
3021: }
3022: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
3023: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
3024: static const DWORD bits[] = {
3025: FROM_LEFT_1ST_BUTTON_PRESSED, // left
3026: RIGHTMOST_BUTTON_PRESSED, // right
3027: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
3028: };
3029: bool prev_status = mouse.buttons[i].status;
3030: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
3031:
3032: if(!prev_status && mouse.buttons[i].status) {
3033: mouse.buttons[i].pressed_times++;
3034: mouse.buttons[i].pressed_position.x = mouse.position.x;
3035: mouse.buttons[i].pressed_position.y = mouse.position.x;
3036: mouse.status |= 2 << (i * 2);
3037: } else if(prev_status && !mouse.buttons[i].status) {
3038: mouse.buttons[i].released_times++;
3039: mouse.buttons[i].released_position.x = mouse.position.x;
3040: mouse.buttons[i].released_position.y = mouse.position.x;
3041: mouse.status |= 4 << (i * 2);
1.1.1.14 root 3042: }
3043: }
3044: }
1.1.1.24 root 3045: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.33 root 3046: // update keyboard flags in bios data area
1.1.1.35! root 3047: if(ir[i].Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) {
! 3048: mem[0x417] |= 0x40;
1.1.1.33 root 3049: } else {
1.1.1.35! root 3050: mem[0x417] &= ~0x40;
1.1.1.33 root 3051: }
1.1.1.35! root 3052: if(ir[i].Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) {
! 3053: mem[0x417] |= 0x20;
1.1.1.33 root 3054: } else {
1.1.1.35! root 3055: mem[0x417] &= ~0x20;
! 3056: }
! 3057: if(ir[i].Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) {
! 3058: mem[0x417] |= 0x10;
! 3059: } else {
! 3060: mem[0x417] &= ~0x10;
1.1.1.33 root 3061: }
3062: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3063: mem[0x417] |= 0x08;
3064: } else {
3065: mem[0x417] &= ~0x08;
3066: }
1.1.1.35! root 3067: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
! 3068: mem[0x417] |= 0x04;
1.1.1.33 root 3069: } else {
1.1.1.35! root 3070: mem[0x417] &= ~0x04;
1.1.1.33 root 3071: }
3072: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3073: if(!(mem[0x417] & 0x03)) {
3074: mem[0x417] |= 0x02; // left shift
3075: }
3076: } else {
3077: mem[0x417] &= ~0x03;
3078: }
1.1.1.35! root 3079: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) {
! 3080: mem[0x418] |= 0x02;
! 3081: } else {
! 3082: mem[0x418] &= ~0x02;
! 3083: }
! 3084: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
! 3085: mem[0x418] |= 0x01;
! 3086: } else {
! 3087: mem[0x418] &= ~0x01;
! 3088: }
1.1.1.33 root 3089:
1.1.1.28 root 3090: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 3091: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.33 root 3092: kbd_status |= 1;
3093:
3094: // update dos key buffer
3095: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
3096: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
3097:
3098: if(ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 3099: // make
1.1.1.24 root 3100: kbd_data &= 0x7f;
3101:
1.1.1.33 root 3102: if(chr == 0x00) {
1.1.1.24 root 3103: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3104: if(scn >= 0x3b && scn <= 0x44) {
3105: scn += 0x68 - 0x3b; // F1 to F10
3106: } else if(scn == 0x57 || scn == 0x58) {
3107: scn += 0x8b - 0x57; // F11 & F12
3108: } else if(scn >= 0x47 && scn <= 0x53) {
3109: scn += 0x97 - 0x47; // edit/arrow clusters
3110: } else if(scn == 0x35) {
3111: scn = 0xa4; // keypad /
3112: }
3113: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3114: if(scn == 0x07) {
3115: chr = 0x1e; // Ctrl+^
3116: } else if(scn == 0x0c) {
3117: chr = 0x1f; // Ctrl+_
3118: } else if(scn >= 0x35 && scn <= 0x58) {
3119: static const UINT8 ctrl_map[] = {
3120: 0x95, // keypad /
3121: 0,
3122: 0x96, // keypad *
3123: 0, 0, 0,
3124: 0x5e, // F1
3125: 0x5f, // F2
3126: 0x60, // F3
3127: 0x61, // F4
3128: 0x62, // F5
3129: 0x63, // F6
3130: 0x64, // F7
3131: 0x65, // F8
3132: 0x66, // F9
3133: 0x67, // F10
3134: 0,
3135: 0,
3136: 0x77, // Home
3137: 0x8d, // Up
3138: 0x84, // PgUp
3139: 0x8e, // keypad -
3140: 0x73, // Left
3141: 0x8f, // keypad center
3142: 0x74, // Right
3143: 0x90, // keyapd +
3144: 0x75, // End
3145: 0x91, // Down
3146: 0x76, // PgDn
3147: 0x92, // Insert
3148: 0x93, // Delete
3149: 0, 0, 0,
3150: 0x89, // F11
3151: 0x8a, // F12
3152: };
3153: scn = ctrl_map[scn - 0x35];
3154: }
3155: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3156: if(scn >= 0x3b && scn <= 0x44) {
3157: scn += 0x54 - 0x3b; // F1 to F10
3158: } else if(scn == 0x57 || scn == 0x58) {
3159: scn += 0x87 - 0x57; // F11 & F12
3160: }
3161: } else if(scn == 0x57 || scn == 0x58) {
3162: scn += 0x85 - 0x57;
3163: }
3164: // ignore shift, ctrl, alt, win and menu keys
3165: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1.1.1.32 root 3166: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 3167: #ifdef USE_SERVICE_THREAD
! 3168: EnterCriticalSection(&key_buf_crit_sect);
! 3169: #endif
1.1.1.32 root 3170: if(chr == 0) {
3171: key_buf_char->write(0x00);
3172: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
3173: }
3174: key_buf_char->write(chr);
3175: key_buf_scan->write(scn);
1.1.1.35! root 3176: #ifdef USE_SERVICE_THREAD
! 3177: LeaveCriticalSection(&key_buf_crit_sect);
! 3178: #endif
1.1.1.24 root 3179: }
3180: }
3181: } else {
3182: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3183: chr = 0;
3184: if(scn >= 0x02 && scn <= 0x0e) {
3185: scn += 0x78 - 0x02; // 1 to 0 - =
3186: }
3187: }
1.1.1.32 root 3188: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 3189: #ifdef USE_SERVICE_THREAD
! 3190: EnterCriticalSection(&key_buf_crit_sect);
! 3191: #endif
1.1.1.32 root 3192: key_buf_char->write(chr);
3193: key_buf_scan->write(scn);
1.1.1.35! root 3194: #ifdef USE_SERVICE_THREAD
! 3195: LeaveCriticalSection(&key_buf_crit_sect);
! 3196: #endif
1.1.1.32 root 3197: }
1.1.1.24 root 3198: }
1.1.1.33 root 3199: } else if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) {
3200: // ctrl-break, ctrl-c
3201: if(scn == 0x46) {
3202: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 3203: #ifdef USE_SERVICE_THREAD
! 3204: EnterCriticalSection(&key_buf_crit_sect);
! 3205: #endif
1.1.1.33 root 3206: key_buf_char->write(0x00);
3207: key_buf_scan->write(0x00);
1.1.1.35! root 3208: #ifdef USE_SERVICE_THREAD
! 3209: LeaveCriticalSection(&key_buf_crit_sect);
! 3210: #endif
1.1.1.33 root 3211: }
3212: ctrl_break_pressed = true;
3213: mem[0x471] = 0x80;
3214: raise_int_1bh = true;
3215: } else {
3216: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 3217: #ifdef USE_SERVICE_THREAD
! 3218: EnterCriticalSection(&key_buf_crit_sect);
! 3219: #endif
1.1.1.33 root 3220: key_buf_char->write(chr);
3221: key_buf_scan->write(scn);
1.1.1.35! root 3222: #ifdef USE_SERVICE_THREAD
! 3223: LeaveCriticalSection(&key_buf_crit_sect);
! 3224: #endif
1.1.1.33 root 3225: }
3226: ctrl_c_pressed = (scn == 0x2e);
3227: }
3228: } else {
3229: // break
3230: kbd_data |= 0x80;
1.1 root 3231: }
1.1.1.24 root 3232: result = key_changed = true;
1.1 root 3233: }
3234: }
3235: }
3236: }
1.1.1.35! root 3237: #ifdef USE_SERVICE_THREAD
! 3238: LeaveCriticalSection(&input_crit_sect);
! 3239: #endif
1.1.1.24 root 3240: return(result);
1.1.1.8 root 3241: }
3242:
1.1.1.14 root 3243: bool update_key_buffer()
1.1.1.8 root 3244: {
1.1.1.35! root 3245: if(update_console_input()) {
! 3246: return(true);
! 3247: }
! 3248: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 3249: #ifdef USE_SERVICE_THREAD
! 3250: EnterCriticalSection(&key_buf_crit_sect);
! 3251: #endif
! 3252: bool empty = key_buf_char->empty();
! 3253: #ifdef USE_SERVICE_THREAD
! 3254: LeaveCriticalSection(&key_buf_crit_sect);
! 3255: #endif
! 3256: if(!empty) return(true);
! 3257: }
! 3258: return(false);
1.1.1.8 root 3259: }
3260:
1.1.1.20 root 3261: /* ----------------------------------------------------------------------------
3262: MS-DOS virtual machine
3263: ---------------------------------------------------------------------------- */
3264:
1.1.1.32 root 3265: static const struct {
1.1.1.33 root 3266: char *name;
3267: DWORD lcid;
3268: char *std;
3269: char *dlt;
3270: } tz_table[] = {
3271: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
3272: // 0 GMT Greenwich Mean Time GMT0
3273: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
3274: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
3275: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
3276: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
3277: // 2 FST FDT Fernando De Noronha Std FST2FDT
3278: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3279: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3280: // 3 BST Brazil Standard Time BST3
3281: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
3282: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
3283: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
3284: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
3285: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
3286: // 3 GST Greenland Standard Time GST3
3287: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
3288: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
3289: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
3290: // 4 AST ADT Atlantic Standard Time AST4ADT
3291: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
3292: // 4 WST WDT Western Standard (Brazil) WST4WDT
3293: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
3294: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
3295: // 5 EST EDT Eastern Standard Time EST5EDT
3296: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
3297: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
3298: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
3299: // 5 CST CDT Chile Standard Time CST5CDT
3300: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
3301: // 5 AST ADT Acre Standard Time AST5ADT
3302: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
3303: // 5 CST CDT Cuba Standard Time CST5CDT
3304: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
3305: // 6 CST CDT Central Standard Time CST6CDT
3306: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
3307: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
3308: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
3309: // 6 EST EDT Easter Island Standard EST6EDT
3310: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
3311: // 7 MST MDT Mountain Standard Time MST7MDT
3312: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
3313: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
3314: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
3315: // 8 PST PDT Pacific Standard Time PST8PDT
3316: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
3317: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
3318: // 9 AKS AKD Alaska Standard Time AKS9AKD
3319: // 9 YST YDT Yukon Standard Time YST9YST
3320: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
3321: // 10 HST HDT Hawaii Standard Time HST10HDT
3322: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
3323: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
3324: // 11 SST Samoa Standard Time SST11
3325: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
3326: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
3327: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
3328: // -10 GST Guam Standard Time GST-10
3329: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
3330: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
3331: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
3332: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
3333: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
3334: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
3335: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
3336: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
3337: // -9 JST Japan Standard Time JST-9
3338: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
3339: // -9 KST KDT Korean Standard Time KST-9KDT
3340: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
3341: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
3342: // -8 HKT Hong Kong Time HKT-8
3343: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
3344: // -8 CCT China Coast Time CCT-8
3345: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
3346: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
3347: // -8 SST Singapore Standard Time SST-8
3348: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
3349: // -8 WAS WAD Western Australian Standard WAS-8WAD
3350: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
3351: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
3352: // -7:30 JT Java Standard Time JST-7:30
3353: // -7 NST North Sumatra Time NST-7
3354: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
3355: // -5:30 IST Indian Standard Time IST-5:30
3356: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
3357: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
3358: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
3359: // -3 MSK MSD Moscow Winter Time MSK-3MSD
3360: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
3361: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
3362: // -2 EET Eastern Europe Time EET-2
3363: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
3364: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
3365: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
3366: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
3367: // -2 IST IDT Israel Standard Time IST-2IDT
3368: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
3369: // -1 MEZ MES Middle European Time MEZ-1MES
3370: // -1 SWT SST Swedish Winter Time SWT-1SST
3371: // -1 FWT FST French Winter Time FWT-1FST
3372: // -1 CET CES Central European Time CET-1CES
3373: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
3374: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
3375: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
3376: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
3377: // -1 WAT West African Time WAT-1
3378: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
3379: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
3380: // 0 UTC Universal Coordinated Time UTC0
3381: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
3382: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
3383: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
3384: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
3385: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
3386: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
3387: };
3388:
3389: static const struct {
1.1.1.32 root 3390: UINT16 code;
3391: char *message_english;
3392: char *message_japanese;
3393: } standard_error_table[] = {
3394: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3395: {0x02, "File not found", "�t�@�C����������܂���."},
3396: {0x03, "Path not found", "�p�X��������܂���."},
3397: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3398: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3399: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3400: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3401: {0x08, "Insufficient memory", "������������܂���."},
3402: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3403: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3404: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3405: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3406: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3407: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3408: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3409: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3410: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3411: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3412: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3413: {0x15, "Not ready", "�������ł��Ă��܂���."},
3414: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3415: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3416: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3417: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3418: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3419: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3420: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3421: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3422: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3423: {0x1F, "General failure", "�G���[�ł�."},
3424: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3425: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3426: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3427: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3428: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3429: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3430: {0x26, "Out of input", "���͂��I���܂���."},
3431: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3432: /*
3433: {0x32, "Network request not supported", NULL},
3434: {0x33, "Remote computer not listening", NULL},
3435: {0x34, "Duplicate name on network", NULL},
3436: {0x35, "Network name not found", NULL},
3437: {0x36, "Network busy", NULL},
3438: {0x37, "Network device no longer exists", NULL},
3439: {0x38, "Network BIOS command limit exceeded", NULL},
3440: {0x39, "Network adapter hardware error", NULL},
3441: {0x3A, "Incorrect response from network", NULL},
3442: {0x3B, "Unexpected network error", NULL},
3443: {0x3C, "Incompatible remote adapter", NULL},
3444: {0x3D, "Print queue full", NULL},
3445: {0x3E, "Queue not full", NULL},
3446: {0x3F, "Not enough space to print file", NULL},
3447: {0x40, "Network name was deleted", NULL},
3448: {0x41, "Network: Access denied", NULL},
3449: {0x42, "Network device type incorrect", NULL},
3450: {0x43, "Network name not found", NULL},
3451: {0x44, "Network name limit exceeded", NULL},
3452: {0x45, "Network BIOS session limit exceeded", NULL},
3453: {0x46, "Temporarily paused", NULL},
3454: {0x47, "Network request not accepted", NULL},
3455: {0x48, "Network print/disk redirection paused", NULL},
3456: {0x49, "Network software not installed", NULL},
3457: {0x4A, "Unexpected adapter close", NULL},
3458: */
3459: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
1.1.1.33 root 3460: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
1.1.1.32 root 3461: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3462: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3463: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3464: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3465: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3466: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3467: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3468: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
3469: /*
3470: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3471: {0x65, "Not ready", "�������ł��Ă��܂���."},
3472: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3473: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3474: {0x68, "Door open", "���o�[���܂��Ă��܂���."
3475: */
3476: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3477: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3478: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3479: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3480: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3481: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3482: };
3483:
3484: static const struct {
3485: UINT16 code;
3486: char *message_english;
3487: char *message_japanese;
3488: } param_error_table[] = {
3489: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3490: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3491: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3492: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3493: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3494: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3495: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3496: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3497: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3498: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3499: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3500: };
3501:
3502: static const struct {
3503: UINT16 code;
3504: char *message_english;
3505: char *message_japanese;
3506: } critical_error_table[] = {
3507: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3508: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3509: {0x02, "Not ready", "�������ł��Ă��܂���."},
3510: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3511: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3512: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3513: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3514: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3515: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3516: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3517: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3518: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3519: {0x0C, "General failure", "�G���[�ł�."},
3520: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3521: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3522: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3523: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3524: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3525: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3526: {0x13, "Out of input", "���͂��I���܂���."},
3527: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3528: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3529: };
3530:
1.1.1.20 root 3531: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3532: int msdos_psp_get_file_table(int fd, int psp_seg);
3533: void msdos_putch(UINT8 data);
1.1.1.35! root 3534: #ifdef USE_SERVICE_THREAD
! 3535: void msdos_putch_tmp(UINT8 data);
! 3536: #endif
1.1.1.20 root 3537:
1.1 root 3538: // process info
3539:
3540: process_t *msdos_process_info_create(UINT16 psp_seg)
3541: {
3542: for(int i = 0; i < MAX_PROCESS; i++) {
3543: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3544: memset(&process[i], 0, sizeof(process_t));
3545: process[i].psp = psp_seg;
3546: return(&process[i]);
3547: }
3548: }
3549: fatalerror("too many processes\n");
3550: return(NULL);
3551: }
3552:
1.1.1.33 root 3553: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error)
1.1 root 3554: {
3555: for(int i = 0; i < MAX_PROCESS; i++) {
3556: if(process[i].psp == psp_seg) {
3557: return(&process[i]);
3558: }
3559: }
1.1.1.33 root 3560: if(show_error) {
3561: fatalerror("invalid psp address\n");
3562: }
1.1 root 3563: return(NULL);
3564: }
3565:
1.1.1.33 root 3566: process_t *msdos_process_info_get(UINT16 psp_seg)
3567: {
3568: return(msdos_process_info_get(psp_seg, true));
3569: }
3570:
1.1.1.23 root 3571: void msdos_sda_update(int psp_seg)
3572: {
3573: sda_t *sda = (sda_t *)(mem + SDA_TOP);
3574:
3575: for(int i = 0; i < MAX_PROCESS; i++) {
3576: if(process[i].psp == psp_seg) {
3577: sda->switchar = process[i].switchar;
3578: sda->current_dta.w.l = process[i].dta.w.l;
3579: sda->current_dta.w.h = process[i].dta.w.h;
3580: sda->current_psp = process[i].psp;
3581: break;
3582: }
3583: }
3584: sda->malloc_strategy = malloc_strategy;
3585: sda->return_code = retval;
3586: sda->current_drive = _getdrive();
3587: }
3588:
1.1.1.13 root 3589: // dta info
3590:
3591: void msdos_dta_info_init()
3592: {
1.1.1.14 root 3593: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 3594: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3595: }
3596: }
3597:
3598: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
3599: {
3600: dtainfo_t *free_dta = NULL;
1.1.1.14 root 3601: for(int i = 0; i < MAX_DTAINFO; i++) {
3602: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
3603: if(free_dta == NULL) {
1.1.1.13 root 3604: free_dta = &dtalist[i];
3605: }
1.1.1.14 root 3606: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 3607: return(&dtalist[i]);
3608: }
3609: }
1.1.1.14 root 3610: if(free_dta) {
1.1.1.13 root 3611: free_dta->psp = psp_seg;
3612: free_dta->dta = dta_laddr;
3613: return(free_dta);
3614: }
3615: fatalerror("too many dta\n");
3616: return(NULL);
3617: }
3618:
3619: void msdos_dta_info_free(UINT16 psp_seg)
3620: {
1.1.1.14 root 3621: for(int i = 0; i < MAX_DTAINFO; i++) {
3622: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 3623: FindClose(dtalist[i].find_handle);
3624: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3625: }
3626: }
3627: }
3628:
1.1 root 3629: void msdos_cds_update(int drv)
3630: {
3631: cds_t *cds = (cds_t *)(mem + CDS_TOP);
3632:
3633: memset(mem + CDS_TOP, 0, CDS_SIZE);
3634: sprintf(cds->path_name, "%c:\\", 'A' + drv);
3635: cds->drive_attrib = 0x4000; // physical drive
3636: cds->physical_drive_number = drv;
3637: }
3638:
1.1.1.17 root 3639: // nls information tables
3640:
3641: // uppercase table (func 6502h)
3642: void msdos_upper_table_update()
3643: {
3644: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3645: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3646: UINT8 c[4];
1.1.1.33 root 3647: *(UINT32 *)c = 0; // reset internal conversion state
3648: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.17 root 3649: c[0] = 0x80 + i;
3650: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
3651: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3652: }
3653: }
3654:
1.1.1.23 root 3655: // lowercase table (func 6503h)
3656: void msdos_lower_table_update()
3657: {
3658: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
3659: for(unsigned i = 0; i < 0x80; ++i) {
3660: UINT8 c[4];
1.1.1.33 root 3661: *(UINT32 *)c = 0; // reset internal conversion state
3662: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.23 root 3663: c[0] = 0x80 + i;
3664: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
3665: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3666: }
3667: }
3668:
1.1.1.17 root 3669: // filename uppercase table (func 6504h)
3670: void msdos_filename_upper_table_init()
3671: {
3672: // depended on (file)system, not on active codepage
3673: // temporary solution: just filling data
3674: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3675: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3676: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
3677: }
3678: }
3679:
3680: // filaname terminator table (func 6505h)
3681: void msdos_filename_terminator_table_init()
3682: {
3683: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
3684: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
3685:
3686: data[2] = 1; // marker? (permissible character value)
3687: data[3] = 0x00; // 00h...FFh
3688: data[4] = 0xff;
3689: data[5] = 0; // marker? (excluded character)
3690: data[6] = 0x00; // 00h...20h
3691: data[7] = 0x20;
3692: data[8] = 2; // marker? (illegal characters for filename)
3693: data[9] = (UINT8)strlen(illegal_chars);
3694: memcpy(data + 10, illegal_chars, data[9]);
3695:
3696: // total length
3697: *(UINT16 *)data = (10 - 2) + data[9];
3698: }
3699:
3700: // collating table (func 6506h)
3701: void msdos_collating_table_update()
3702: {
3703: // temporary solution: just filling data
3704: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 3705: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 3706: mem[COLLATING_TABLE_TOP + 2 + i] = i;
3707: }
3708: }
3709:
1.1 root 3710: // dbcs
3711:
3712: void msdos_dbcs_table_update()
3713: {
3714: UINT8 dbcs_data[DBCS_SIZE];
3715: memset(dbcs_data, 0, sizeof(dbcs_data));
3716:
3717: CPINFO info;
3718: GetCPInfo(active_code_page, &info);
3719:
3720: if(info.MaxCharSize != 1) {
3721: for(int i = 0;; i += 2) {
3722: UINT8 lo = info.LeadByte[i + 0];
3723: UINT8 hi = info.LeadByte[i + 1];
3724: dbcs_data[2 + i + 0] = lo;
3725: dbcs_data[2 + i + 1] = hi;
3726: if(lo == 0 && hi == 0) {
3727: dbcs_data[0] = i + 2;
3728: break;
3729: }
3730: }
3731: } else {
3732: dbcs_data[0] = 2; // ???
3733: }
3734: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
3735: }
3736:
1.1.1.17 root 3737: void msdos_dbcs_table_finish()
3738: {
1.1.1.32 root 3739: if(system_code_page != _getmbcp()) {
1.1.1.17 root 3740: _setmbcp(system_code_page);
3741: }
1.1.1.32 root 3742: if(console_code_page != GetConsoleCP()) {
3743: SetConsoleCP(console_code_page);
3744: SetConsoleOutputCP(console_code_page);
3745: }
1.1.1.17 root 3746: }
3747:
3748: void msdos_nls_tables_init()
1.1 root 3749: {
1.1.1.32 root 3750: active_code_page = console_code_page = GetConsoleCP();
3751: system_code_page = _getmbcp();
3752:
3753: if(active_code_page != system_code_page) {
3754: if(_setmbcp(active_code_page) != 0) {
3755: active_code_page = system_code_page;
3756: }
3757: }
3758:
1.1.1.17 root 3759: msdos_upper_table_update();
1.1.1.23 root 3760: msdos_lower_table_update();
1.1.1.17 root 3761: msdos_filename_terminator_table_init();
3762: msdos_filename_upper_table_init();
3763: msdos_collating_table_update();
1.1 root 3764: msdos_dbcs_table_update();
3765: }
3766:
1.1.1.17 root 3767: void msdos_nls_tables_update()
1.1 root 3768: {
1.1.1.17 root 3769: msdos_dbcs_table_update();
3770: msdos_upper_table_update();
1.1.1.23 root 3771: msdos_lower_table_update();
3772: // msdos_collating_table_update();
1.1 root 3773: }
3774:
3775: int msdos_lead_byte_check(UINT8 code)
3776: {
3777: UINT8 *dbcs_table = mem + DBCS_TABLE;
3778:
3779: for(int i = 0;; i += 2) {
3780: UINT8 lo = dbcs_table[i + 0];
3781: UINT8 hi = dbcs_table[i + 1];
3782: if(lo == 0 && hi == 0) {
3783: break;
3784: }
3785: if(lo <= code && code <= hi) {
3786: return(1);
3787: }
3788: }
3789: return(0);
3790: }
3791:
1.1.1.20 root 3792: int msdos_ctrl_code_check(UINT8 code)
3793: {
1.1.1.22 root 3794: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 3795: }
3796:
1.1 root 3797: // file control
3798:
1.1.1.14 root 3799: char *msdos_remove_double_quote(char *path)
3800: {
3801: static char tmp[MAX_PATH];
3802:
3803: memset(tmp, 0, sizeof(tmp));
3804: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
3805: memcpy(tmp, path + 1, strlen(path) - 2);
3806: } else {
3807: strcpy(tmp, path);
3808: }
3809: return(tmp);
3810: }
3811:
1.1.1.32 root 3812: char *msdos_remove_end_separator(char *path)
3813: {
3814: static char tmp[MAX_PATH];
3815:
3816: strcpy(tmp, path);
3817: int len = strlen(tmp);
3818: if(len > 3 && tmp[len - 1] == '\\') {
3819: tmp[len - 1] = '\0';
3820: }
3821: return(tmp);
3822: }
3823:
1.1.1.14 root 3824: char *msdos_combine_path(char *dir, const char *file)
3825: {
3826: static char tmp[MAX_PATH];
3827: char *tmp_dir = msdos_remove_double_quote(dir);
3828:
3829: if(strlen(tmp_dir) == 0) {
3830: strcpy(tmp, file);
3831: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
3832: sprintf(tmp, "%s%s", tmp_dir, file);
3833: } else {
3834: sprintf(tmp, "%s\\%s", tmp_dir, file);
3835: }
3836: return(tmp);
3837: }
3838:
1.1 root 3839: char *msdos_trimmed_path(char *path, int lfn)
3840: {
3841: static char tmp[MAX_PATH];
3842:
3843: if(lfn) {
3844: strcpy(tmp, path);
3845: } else {
3846: // remove space in the path
3847: char *src = path, *dst = tmp;
3848:
3849: while(*src != '\0') {
3850: if(msdos_lead_byte_check(*src)) {
3851: *dst++ = *src++;
3852: *dst++ = *src++;
3853: } else if(*src != ' ') {
3854: *dst++ = *src++;
3855: } else {
3856: src++; // skip space
3857: }
3858: }
3859: *dst = '\0';
3860: }
1.1.1.14 root 3861: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
3862: // redirect C:\COMMAND.COM to comspec_path
3863: strcpy(tmp, comspec_path);
3864: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
3865: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
3866: static int root_drive_protected = -1;
3867: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
3868: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
3869:
3870: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
3871: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
3872: strcpy(name, name_temp);
3873: name_temp[0] = '\0';
3874:
3875: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
3876: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
3877: if(root_drive_protected == -1) {
3878: FILE *fp = NULL;
3879:
3880: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
3881: root_drive_protected = 1;
3882: try {
3883: if((fp = fopen(temp, "w")) != NULL) {
3884: if(fprintf(fp, "TEST") == 4) {
3885: root_drive_protected = 0;
3886: }
3887: }
3888: } catch(...) {
3889: }
3890: if(fp != NULL) {
3891: fclose(fp);
3892: }
3893: if(_access(temp, 0) == 0) {
3894: remove(temp);
3895: }
3896: }
3897: if(root_drive_protected == 1) {
3898: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
3899: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
3900: strcpy(tmp, msdos_combine_path(temp, name));
3901: }
3902: }
3903: }
3904: }
3905: }
1.1 root 3906: return(tmp);
3907: }
3908:
1.1.1.28 root 3909: char *msdos_get_multiple_short_path(char *src)
3910: {
1.1.1.32 root 3911: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 3912: static char env_path[ENV_SIZE];
3913: char tmp[ENV_SIZE], *token;
3914:
3915: memset(env_path, 0, sizeof(env_path));
3916: strcpy(tmp, src);
3917: token = my_strtok(tmp, ";");
3918:
3919: while(token != NULL) {
3920: if(token[0] != '\0') {
3921: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.32 root 3922: if(path != NULL && strlen(path) != 0) {
3923: if(env_path[0] != '\0') {
3924: strcat(env_path, ";");
3925: }
1.1.1.28 root 3926: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32 root 3927: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 3928: } else {
3929: my_strupr(short_path);
1.1.1.32 root 3930: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 3931: }
3932: }
3933: }
3934: token = my_strtok(NULL, ";");
3935: }
3936: return(env_path);
3937: }
3938:
1.1 root 3939: bool match(char *text, char *pattern)
3940: {
1.1.1.24 root 3941: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 3942: switch(*pattern) {
1.1 root 3943: case '\0':
3944: return !*text;
3945: case '*':
1.1.1.14 root 3946: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 3947: case '?':
3948: return *text && match(text + 1, pattern + 1);
3949: default:
3950: return (*text == *pattern) && match(text + 1, pattern + 1);
3951: }
3952: }
3953:
3954: bool msdos_match_volume_label(char *path, char *volume)
3955: {
3956: char *p;
3957:
1.1.1.14 root 3958: if(!*volume) {
3959: return false;
3960: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 3961: return msdos_match_volume_label(p + 1, volume);
3962: } else if((p = my_strchr(path, '\\')) != NULL) {
3963: return msdos_match_volume_label(p + 1, volume);
3964: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 3965: char tmp[MAX_PATH];
3966: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
3967: return match(volume, tmp);
1.1 root 3968: } else {
3969: return match(volume, path);
3970: }
3971: }
3972:
3973: char *msdos_fcb_path(fcb_t *fcb)
3974: {
3975: static char tmp[MAX_PATH];
3976: char name[9], ext[4];
3977:
3978: memset(name, 0, sizeof(name));
3979: memcpy(name, fcb->file_name, 8);
3980: strcpy(name, msdos_trimmed_path(name, 0));
3981:
3982: memset(ext, 0, sizeof(ext));
3983: memcpy(ext, fcb->file_name + 8, 3);
3984: strcpy(ext, msdos_trimmed_path(ext, 0));
3985:
3986: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
3987: strcpy(name, "*");
3988: }
3989: if(ext[0] == '\0') {
3990: strcpy(tmp, name);
3991: } else {
3992: if(strcmp(ext, "???") == 0) {
3993: strcpy(ext, "*");
3994: }
3995: sprintf(tmp, "%s.%s", name, ext);
3996: }
3997: return(tmp);
3998: }
3999:
4000: void msdos_set_fcb_path(fcb_t *fcb, char *path)
4001: {
4002: char *ext = my_strchr(path, '.');
4003:
4004: memset(fcb->file_name, 0x20, 8 + 3);
4005: if(ext != NULL && path[0] != '.') {
4006: *ext = '\0';
4007: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
4008: }
4009: memcpy(fcb->file_name, path, strlen(path));
4010: }
4011:
4012: char *msdos_short_path(char *path)
4013: {
4014: static char tmp[MAX_PATH];
4015:
1.1.1.24 root 4016: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
4017: strcpy(tmp, path);
4018: }
1.1 root 4019: my_strupr(tmp);
4020: return(tmp);
4021: }
4022:
1.1.1.13 root 4023: char *msdos_short_name(WIN32_FIND_DATA *fd)
4024: {
4025: static char tmp[MAX_PATH];
4026:
1.1.1.14 root 4027: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4028: strcpy(tmp, fd->cAlternateFileName);
4029: } else {
4030: strcpy(tmp, fd->cFileName);
4031: }
4032: my_strupr(tmp);
4033: return(tmp);
4034: }
4035:
1.1 root 4036: char *msdos_short_full_path(char *path)
4037: {
4038: static char tmp[MAX_PATH];
4039: char full[MAX_PATH], *name;
4040:
1.1.1.14 root 4041: // Full works with non-existent files, but Short does not
1.1 root 4042: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 4043: *tmp = '\0';
4044: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
4045: name[-1] = '\0';
4046: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
4047: if(len == 0) {
4048: strcpy(tmp, full);
4049: } else {
4050: tmp[len++] = '\\';
4051: strcpy(tmp + len, name);
4052: }
4053: }
1.1 root 4054: my_strupr(tmp);
4055: return(tmp);
4056: }
4057:
4058: char *msdos_short_full_dir(char *path)
4059: {
4060: static char tmp[MAX_PATH];
4061: char full[MAX_PATH], *name;
4062:
4063: GetFullPathName(path, MAX_PATH, full, &name);
4064: name[-1] = '\0';
1.1.1.24 root 4065: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
4066: strcpy(tmp, full);
4067: }
1.1 root 4068: my_strupr(tmp);
4069: return(tmp);
4070: }
4071:
4072: char *msdos_local_file_path(char *path, int lfn)
4073: {
4074: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 4075: #if 0
4076: // I have forgotten the reason of this routine... :-(
1.1 root 4077: if(_access(trimmed, 0) != 0) {
4078: process_t *process = msdos_process_info_get(current_psp);
4079: static char tmp[MAX_PATH];
4080:
4081: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
4082: if(_access(tmp, 0) == 0) {
4083: return(tmp);
4084: }
4085: }
1.1.1.14 root 4086: #endif
1.1 root 4087: return(trimmed);
4088: }
4089:
1.1.1.29 root 4090: bool msdos_is_device_path(char *path)
1.1.1.11 root 4091: {
4092: char full[MAX_PATH], *name;
4093:
1.1.1.24 root 4094: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4095: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4096: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4097: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4098: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4099: _stricmp(full, "\\\\.\\COM1") == 0 ||
4100: _stricmp(full, "\\\\.\\COM2") == 0 ||
4101: _stricmp(full, "\\\\.\\COM3") == 0 ||
4102: _stricmp(full, "\\\\.\\COM4") == 0 ||
4103: _stricmp(full, "\\\\.\\COM5") == 0 ||
4104: _stricmp(full, "\\\\.\\COM6") == 0 ||
4105: _stricmp(full, "\\\\.\\COM7") == 0 ||
4106: _stricmp(full, "\\\\.\\COM8") == 0 ||
4107: _stricmp(full, "\\\\.\\COM9") == 0 ||
4108: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4109: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4110: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4111: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4112: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4113: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4114: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4115: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4116: _stricmp(full, "\\\\.\\LPT9") == 0) {
4117: return(true);
4118: } else if(name != NULL) {
4119: if(_stricmp(name, "CLOCK$" ) == 0 ||
4120: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 4121: _stricmp(name, "EMMXXXX0") == 0 ||
4122: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 4123: return(true);
4124: }
4125: }
1.1.1.24 root 4126: }
4127: return(false);
1.1.1.11 root 4128: }
4129:
1.1.1.29 root 4130: bool msdos_is_con_path(char *path)
1.1.1.8 root 4131: {
1.1.1.14 root 4132: char full[MAX_PATH], *name;
1.1.1.8 root 4133:
1.1.1.24 root 4134: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4135: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 4136: }
4137: return(false);
4138: }
4139:
1.1.1.29 root 4140: int msdos_is_comm_path(char *path)
1.1.1.24 root 4141: {
4142: char full[MAX_PATH], *name;
4143:
4144: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4145: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4146: return(1);
4147: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4148: return(2);
4149: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4150: return(3);
4151: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4152: return(4);
1.1.1.24 root 4153: }
4154: }
1.1.1.29 root 4155: return(0);
4156: }
4157:
1.1.1.30 root 4158: int msdos_is_prn_path(char *path)
4159: {
4160: char full[MAX_PATH], *name;
4161:
4162: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4163: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4164: return(1);
4165: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4166: return(1);
4167: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4168: return(2);
4169: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4170: return(3);
4171: }
4172: }
4173: return(0);
4174: }
4175:
1.1.1.29 root 4176: char *msdos_create_comm_path(char *path, int port)
4177: {
4178: static char tmp[MAX_PATH];
4179: char *p = NULL;
4180:
4181: sprintf(tmp, "COM%d", port);
4182: if((p = strchr(path, ':')) != NULL) {
4183: strcat(tmp, p);
4184: }
4185: return(tmp);
1.1.1.24 root 4186: }
4187:
4188: bool msdos_is_existing_file(char *path)
4189: {
4190: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4191: WIN32_FIND_DATA FindData;
4192: HANDLE hFind;
4193:
4194: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
4195: FindClose(hFind);
4196: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
4197: }
4198: return(false);
1.1.1.8 root 4199: }
4200:
1.1.1.9 root 4201: char *msdos_search_command_com(char *command_path, char *env_path)
4202: {
4203: static char tmp[MAX_PATH];
1.1.1.28 root 4204: char path[ENV_SIZE], *file_name;
1.1.1.9 root 4205:
1.1.1.28 root 4206: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 4207: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
4208: sprintf(file_name, "COMMAND.COM");
4209: if(_access(tmp, 0) == 0) {
4210: return(tmp);
4211: }
4212: }
1.1.1.28 root 4213:
4214: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 4215: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
4216: sprintf(file_name, "COMMAND.COM");
4217: if(_access(tmp, 0) == 0) {
4218: return(tmp);
4219: }
4220: }
1.1.1.28 root 4221:
4222: // check if COMMAND.COM is in the current directory
1.1.1.9 root 4223: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4224: if(_access(tmp, 0) == 0) {
4225: return(tmp);
4226: }
4227: }
1.1.1.28 root 4228:
4229: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4230: strcpy(path, env_path);
4231: char *token = my_strtok(path, ";");
1.1.1.9 root 4232: while(token != NULL) {
1.1.1.14 root 4233: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 4234: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4235: if(_access(tmp, 0) == 0) {
4236: return(tmp);
4237: }
4238: }
4239: token = my_strtok(NULL, ";");
4240: }
4241: return(NULL);
4242: }
4243:
1.1.1.14 root 4244: int msdos_drive_number(const char *path)
1.1 root 4245: {
4246: char tmp[MAX_PATH], *name;
4247:
4248: GetFullPathName(path, MAX_PATH, tmp, &name);
4249: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4250: return(tmp[0] - 'a');
4251: } else {
4252: return(tmp[0] - 'A');
4253: }
4254: }
4255:
4256: char *msdos_volume_label(char *path)
4257: {
4258: static char tmp[MAX_PATH];
4259: char volume[] = "A:\\";
4260:
4261: if(path[1] == ':') {
4262: volume[0] = path[0];
4263: } else {
4264: volume[0] = 'A' + _getdrive() - 1;
4265: }
4266: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4267: memset(tmp, 0, sizeof(tmp));
4268: }
4269: return(tmp);
4270: }
4271:
4272: char *msdos_short_volume_label(char *label)
4273: {
4274: static char tmp[(8 + 1 + 3) + 1];
4275: char *src = label;
4276: int remain = strlen(label);
4277: char *dst_n = tmp;
4278: char *dst_e = tmp + 9;
4279:
4280: strcpy(tmp, " . ");
4281: for(int i = 0; i < 8 && remain > 0; i++) {
4282: if(msdos_lead_byte_check(*src)) {
4283: if(++i == 8) {
4284: break;
4285: }
4286: *dst_n++ = *src++;
4287: remain--;
4288: }
4289: *dst_n++ = *src++;
4290: remain--;
4291: }
4292: if(remain > 0) {
4293: for(int i = 0; i < 3 && remain > 0; i++) {
4294: if(msdos_lead_byte_check(*src)) {
4295: if(++i == 3) {
4296: break;
4297: }
4298: *dst_e++ = *src++;
4299: remain--;
4300: }
4301: *dst_e++ = *src++;
4302: remain--;
4303: }
4304: *dst_e = '\0';
4305: } else {
4306: *dst_n = '\0';
4307: }
4308: my_strupr(tmp);
4309: return(tmp);
4310: }
4311:
1.1.1.13 root 4312: errno_t msdos_maperr(unsigned long oserrno)
4313: {
4314: _doserrno = oserrno;
1.1.1.14 root 4315: switch(oserrno) {
1.1.1.13 root 4316: case ERROR_FILE_NOT_FOUND: // 2
4317: case ERROR_PATH_NOT_FOUND: // 3
4318: case ERROR_INVALID_DRIVE: // 15
4319: case ERROR_NO_MORE_FILES: // 18
4320: case ERROR_BAD_NETPATH: // 53
4321: case ERROR_BAD_NET_NAME: // 67
4322: case ERROR_BAD_PATHNAME: // 161
4323: case ERROR_FILENAME_EXCED_RANGE: // 206
4324: return ENOENT;
4325: case ERROR_TOO_MANY_OPEN_FILES: // 4
4326: return EMFILE;
4327: case ERROR_ACCESS_DENIED: // 5
4328: case ERROR_CURRENT_DIRECTORY: // 16
4329: case ERROR_NETWORK_ACCESS_DENIED: // 65
4330: case ERROR_CANNOT_MAKE: // 82
4331: case ERROR_FAIL_I24: // 83
4332: case ERROR_DRIVE_LOCKED: // 108
4333: case ERROR_SEEK_ON_DEVICE: // 132
4334: case ERROR_NOT_LOCKED: // 158
4335: case ERROR_LOCK_FAILED: // 167
4336: return EACCES;
4337: case ERROR_INVALID_HANDLE: // 6
4338: case ERROR_INVALID_TARGET_HANDLE: // 114
4339: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4340: return EBADF;
4341: case ERROR_ARENA_TRASHED: // 7
4342: case ERROR_NOT_ENOUGH_MEMORY: // 8
4343: case ERROR_INVALID_BLOCK: // 9
4344: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4345: return ENOMEM;
4346: case ERROR_BAD_ENVIRONMENT: // 10
4347: return E2BIG;
4348: case ERROR_BAD_FORMAT: // 11
4349: return ENOEXEC;
4350: case ERROR_NOT_SAME_DEVICE: // 17
4351: return EXDEV;
4352: case ERROR_FILE_EXISTS: // 80
4353: case ERROR_ALREADY_EXISTS: // 183
4354: return EEXIST;
4355: case ERROR_NO_PROC_SLOTS: // 89
4356: case ERROR_MAX_THRDS_REACHED: // 164
4357: case ERROR_NESTING_NOT_ALLOWED: // 215
4358: return EAGAIN;
4359: case ERROR_BROKEN_PIPE: // 109
4360: return EPIPE;
4361: case ERROR_DISK_FULL: // 112
4362: return ENOSPC;
4363: case ERROR_WAIT_NO_CHILDREN: // 128
4364: case ERROR_CHILD_NOT_COMPLETE: // 129
4365: return ECHILD;
4366: case ERROR_DIR_NOT_EMPTY: // 145
4367: return ENOTEMPTY;
4368: }
1.1.1.14 root 4369: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 4370: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4371: return EACCES;
4372: }
1.1.1.14 root 4373: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 4374: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4375: return ENOEXEC;
4376: }
4377: return EINVAL;
4378: }
4379:
4380: int msdos_open(const char *filename, int oflag)
4381: {
1.1.1.14 root 4382: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 4383: return _open(filename, oflag);
4384: }
1.1.1.14 root 4385:
4386: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 4387: DWORD disposition;
1.1.1.14 root 4388: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4389: default:
1.1.1.13 root 4390: case _O_EXCL:
4391: disposition = OPEN_EXISTING;
4392: break;
4393: case _O_CREAT:
4394: disposition = OPEN_ALWAYS;
4395: break;
4396: case _O_CREAT | _O_EXCL:
4397: case _O_CREAT | _O_TRUNC | _O_EXCL:
4398: disposition = CREATE_NEW;
4399: break;
4400: case _O_TRUNC:
4401: case _O_TRUNC | _O_EXCL:
4402: disposition = TRUNCATE_EXISTING;
4403: break;
4404: case _O_CREAT | _O_TRUNC:
4405: disposition = CREATE_ALWAYS;
4406: break;
4407: }
1.1.1.14 root 4408:
1.1.1.13 root 4409: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
4410: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4411: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4412: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4413: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4414: // Retry without FILE_WRITE_ATTRIBUTES.
4415: h = CreateFile(filename, GENERIC_READ,
4416: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4417: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4418: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4419: errno = msdos_maperr(GetLastError());
4420: return -1;
4421: }
4422: }
1.1.1.14 root 4423:
1.1.1.13 root 4424: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 4425: if(fd == -1) {
1.1.1.13 root 4426: CloseHandle(h);
4427: }
4428: return fd;
4429: }
4430:
1.1.1.14 root 4431: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 4432: {
4433: static int id = 0;
4434: char full[MAX_PATH], *name;
4435:
4436: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4437: strcpy(file_handler[fd].path, full);
4438: } else {
4439: strcpy(file_handler[fd].path, path);
4440: }
1.1.1.14 root 4441: // isatty makes no distinction between CON & NUL
4442: // GetFileSize fails on CON, succeeds on NUL
4443: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
4444: info = 0x8084;
4445: atty = 0;
4446: } else if(!atty && info == 0x80d3) {
4447: info = msdos_drive_number(".");
4448: }
1.1 root 4449: file_handler[fd].valid = 1;
4450: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
4451: file_handler[fd].atty = atty;
4452: file_handler[fd].mode = mode;
4453: file_handler[fd].info = info;
4454: file_handler[fd].psp = psp_seg;
1.1.1.21 root 4455:
4456: // init system file table
4457: if(fd < 20) {
4458: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
4459:
4460: memset(sft, 0, 0x3b);
4461:
4462: *(UINT16 *)(sft + 0x00) = 1;
4463: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
4464: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
4465: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
4466:
4467: if(!(file_handler[fd].info & 0x80)) {
4468: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
4469: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
4470:
4471: FILETIME time, local;
4472: HANDLE hHandle;
4473: WORD dos_date = 0, dos_time = 0;
4474: DWORD file_size = 0;
4475: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
4476: if(GetFileTime(hHandle, NULL, NULL, &time)) {
4477: FileTimeToLocalFileTime(&time, &local);
4478: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
4479: }
4480: file_size = GetFileSize(hHandle, NULL);
4481: }
4482: *(UINT16 *)(sft + 0x0d) = dos_time;
4483: *(UINT16 *)(sft + 0x0f) = dos_date;
4484: *(UINT32 *)(sft + 0x11) = file_size;
4485: }
4486:
4487: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
4488: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
4489: my_strupr(fname);
4490: my_strupr(ext);
4491: memset(sft + 0x20, 0x20, 11);
4492: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
4493: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
4494:
4495: *(UINT16 *)(sft + 0x31) = psp_seg;
4496: }
1.1 root 4497: }
4498:
4499: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
4500: {
4501: strcpy(file_handler[dst].path, file_handler[src].path);
4502: file_handler[dst].valid = 1;
4503: file_handler[dst].id = file_handler[src].id;
4504: file_handler[dst].atty = file_handler[src].atty;
4505: file_handler[dst].mode = file_handler[src].mode;
4506: file_handler[dst].info = file_handler[src].info;
4507: file_handler[dst].psp = psp_seg;
4508: }
4509:
1.1.1.20 root 4510: void msdos_file_handler_close(int fd)
1.1 root 4511: {
4512: file_handler[fd].valid = 0;
1.1.1.21 root 4513:
4514: if(fd < 20) {
4515: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
4516: }
1.1 root 4517: }
4518:
1.1.1.14 root 4519: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 4520: {
1.1.1.14 root 4521: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
4522: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
4523: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 4524: }
4525:
4526: // find file
4527:
4528: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
4529: {
4530: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4531: return(0); // search directory only !!!
4532: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
4533: return(0);
4534: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
4535: return(0);
4536: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4537: return(0);
4538: } else if((attribute & required_mask) != required_mask) {
4539: return(0);
4540: } else {
4541: return(1);
4542: }
4543: }
4544:
1.1.1.13 root 4545: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
4546: {
1.1.1.14 root 4547: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4548: return 1;
4549: }
4550: size_t len = strlen(fd->cFileName);
1.1.1.14 root 4551: if(len > 12) {
1.1.1.13 root 4552: return 0;
4553: }
4554: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 4555: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 4556: return 0;
4557: }
4558: return 1;
4559: }
4560:
1.1 root 4561: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
4562: {
4563: FILETIME local;
4564:
4565: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
4566: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
4567: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
4568:
4569: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
4570: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
4571: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
4572:
4573: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
4574: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
4575: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
4576: }
4577:
4578: // i/o
4579:
4580: void msdos_stdio_reopen()
4581: {
4582: if(!file_handler[0].valid) {
4583: _dup2(DUP_STDIN, 0);
4584: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
4585: }
4586: if(!file_handler[1].valid) {
4587: _dup2(DUP_STDOUT, 1);
4588: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
4589: }
4590: if(!file_handler[2].valid) {
4591: _dup2(DUP_STDERR, 2);
4592: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
4593: }
1.1.1.21 root 4594: if(!file_handler[3].valid) {
4595: _dup2(DUP_STDAUX, 3);
4596: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
4597: }
4598: if(!file_handler[4].valid) {
4599: _dup2(DUP_STDPRN, 4);
4600: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
4601: }
4602: for(int i = 0; i < 5; i++) {
4603: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
4604: msdos_psp_set_file_table(i, i, current_psp);
4605: }
4606: }
1.1 root 4607: }
4608:
4609: int msdos_kbhit()
4610: {
4611: msdos_stdio_reopen();
4612:
1.1.1.20 root 4613: process_t *process = msdos_process_info_get(current_psp);
4614: int fd = msdos_psp_get_file_table(0, current_psp);
4615:
4616: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4617: // stdin is redirected to file
1.1.1.20 root 4618: return(eof(fd) == 0);
1.1 root 4619: }
4620:
4621: // check keyboard status
1.1.1.35! root 4622: if(key_recv != 0) {
1.1 root 4623: return(1);
4624: }
1.1.1.35! root 4625: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 4626: #ifdef USE_SERVICE_THREAD
! 4627: EnterCriticalSection(&key_buf_crit_sect);
! 4628: #endif
! 4629: bool empty = key_buf_char->empty();
! 4630: #ifdef USE_SERVICE_THREAD
! 4631: LeaveCriticalSection(&key_buf_crit_sect);
! 4632: #endif
! 4633: if(!empty) return(1);
! 4634: }
! 4635: return(_kbhit());
1.1 root 4636: }
4637:
4638: int msdos_getch_ex(int echo)
4639: {
4640: static char prev = 0;
4641:
4642: msdos_stdio_reopen();
4643:
1.1.1.20 root 4644: process_t *process = msdos_process_info_get(current_psp);
4645: int fd = msdos_psp_get_file_table(0, current_psp);
4646:
4647: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4648: // stdin is redirected to file
4649: retry:
4650: char data;
1.1.1.20 root 4651: if(_read(fd, &data, 1) == 1) {
1.1 root 4652: char tmp = data;
4653: if(data == 0x0a) {
4654: if(prev == 0x0d) {
4655: goto retry; // CRLF -> skip LF
4656: } else {
4657: data = 0x0d; // LF only -> CR
4658: }
4659: }
4660: prev = tmp;
4661: return(data);
4662: }
4663: return(EOF);
4664: }
4665:
4666: // input from console
1.1.1.5 root 4667: int key_char, key_scan;
1.1.1.33 root 4668: if(key_recv != 0) {
1.1.1.5 root 4669: key_char = (key_code >> 0) & 0xff;
4670: key_scan = (key_code >> 8) & 0xff;
4671: key_code >>= 16;
1.1.1.33 root 4672: key_recv >>= 16;
1.1.1.5 root 4673: } else {
1.1.1.35! root 4674: while(key_buf_char != NULL && key_buf_scan != NULL && !m_halted) {
! 4675: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 4676: #ifdef USE_SERVICE_THREAD
! 4677: EnterCriticalSection(&key_buf_crit_sect);
! 4678: #endif
! 4679: bool empty = key_buf_char->empty();
! 4680: #ifdef USE_SERVICE_THREAD
! 4681: LeaveCriticalSection(&key_buf_crit_sect);
! 4682: #endif
! 4683: if(!empty) break;
! 4684: }
1.1.1.23 root 4685: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
4686: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
4687: if(_kbhit()) {
1.1.1.32 root 4688: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 4689: #ifdef USE_SERVICE_THREAD
! 4690: EnterCriticalSection(&key_buf_crit_sect);
! 4691: #endif
1.1.1.32 root 4692: key_buf_char->write(_getch());
1.1.1.35! root 4693: key_buf_scan->write(0x00);
! 4694: #ifdef USE_SERVICE_THREAD
! 4695: LeaveCriticalSection(&key_buf_crit_sect);
! 4696: #endif
1.1.1.32 root 4697: }
1.1.1.23 root 4698: } else {
4699: Sleep(10);
4700: }
4701: } else {
4702: if(!update_key_buffer()) {
4703: Sleep(10);
4704: }
1.1.1.14 root 4705: }
4706: }
4707: if(m_halted) {
1.1.1.33 root 4708: // insert CR to terminate input loops
1.1.1.14 root 4709: key_char = 0x0d;
4710: key_scan = 0;
1.1.1.32 root 4711: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 4712: #ifdef USE_SERVICE_THREAD
! 4713: EnterCriticalSection(&key_buf_crit_sect);
! 4714: #endif
1.1.1.14 root 4715: key_char = key_buf_char->read();
4716: key_scan = key_buf_scan->read();
1.1.1.35! root 4717: #ifdef USE_SERVICE_THREAD
! 4718: LeaveCriticalSection(&key_buf_crit_sect);
! 4719: #endif
1.1.1.5 root 4720: }
1.1 root 4721: }
4722: if(echo && key_char) {
4723: msdos_putch(key_char);
4724: }
4725: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
4726: }
4727:
4728: inline int msdos_getch()
4729: {
4730: return(msdos_getch_ex(0));
4731: }
4732:
4733: inline int msdos_getche()
4734: {
4735: return(msdos_getch_ex(1));
4736: }
4737:
4738: int msdos_write(int fd, const void *buffer, unsigned int count)
4739: {
4740: static int is_cr = 0;
4741:
4742: if(fd == 1 && !file_handler[1].atty) {
4743: // CR+LF -> LF
4744: UINT8 *buf = (UINT8 *)buffer;
4745: for(unsigned int i = 0; i < count; i++) {
4746: UINT8 data = buf[i];
4747: if(is_cr) {
4748: if(data != 0x0a) {
4749: UINT8 tmp = 0x0d;
4750: _write(1, &tmp, 1);
4751: }
4752: _write(1, &data, 1);
4753: is_cr = 0;
4754: } else if(data == 0x0d) {
4755: is_cr = 1;
4756: } else {
4757: _write(1, &data, 1);
4758: }
4759: }
4760: return(count);
4761: }
1.1.1.14 root 4762: vram_flush();
1.1 root 4763: return(_write(fd, buffer, count));
4764: }
4765:
4766: void msdos_putch(UINT8 data)
1.1.1.35! root 4767: #ifdef USE_SERVICE_THREAD
! 4768: {
! 4769: EnterCriticalSection(&putch_crit_sect);
! 4770: msdos_putch_tmp(data);
! 4771: LeaveCriticalSection(&putch_crit_sect);
! 4772: }
! 4773: void msdos_putch_tmp(UINT8 data)
! 4774: #endif
1.1 root 4775: {
1.1.1.34 root 4776: CONSOLE_SCREEN_BUFFER_INFO csbi;
4777: SMALL_RECT rect;
4778: COORD co;
1.1 root 4779: static int p = 0;
4780: static int is_kanji = 0;
4781: static int is_esc = 0;
4782: static int stored_x;
4783: static int stored_y;
4784: static WORD stored_a;
1.1.1.20 root 4785: static char tmp[64], out[64];
1.1 root 4786:
4787: msdos_stdio_reopen();
4788:
1.1.1.20 root 4789: process_t *process = msdos_process_info_get(current_psp);
4790: int fd = msdos_psp_get_file_table(1, current_psp);
4791:
4792: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4793: // stdout is redirected to file
1.1.1.20 root 4794: msdos_write(fd, &data, 1);
1.1 root 4795: return;
4796: }
1.1.1.23 root 4797: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4798:
4799: // output to console
4800: tmp[p++] = data;
4801:
1.1.1.14 root 4802: vram_flush();
4803:
1.1 root 4804: if(is_kanji) {
4805: // kanji character
4806: is_kanji = 0;
4807: } else if(is_esc) {
4808: // escape sequense
4809: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
4810: p = is_esc = 0;
4811: } else if(tmp[1] == '=' && p == 4) {
4812: co.X = tmp[3] - 0x20;
1.1.1.14 root 4813: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 4814: SetConsoleCursorPosition(hStdout, co);
4815: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 4816: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 4817: cursor_moved = false;
4818: p = is_esc = 0;
4819: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
4820: GetConsoleScreenBufferInfo(hStdout, &csbi);
4821: co.X = csbi.dwCursorPosition.X;
4822: co.Y = csbi.dwCursorPosition.Y;
4823: WORD wAttributes = csbi.wAttributes;
4824:
4825: if(tmp[1] == 'D') {
4826: co.Y++;
4827: } else if(tmp[1] == 'E') {
4828: co.X = 0;
4829: co.Y++;
4830: } else if(tmp[1] == 'M') {
4831: co.Y--;
4832: } else if(tmp[1] == '*') {
1.1.1.14 root 4833: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4834: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4835: co.X = 0;
4836: co.Y = csbi.srWindow.Top;
1.1 root 4837: } else if(tmp[1] == '[') {
4838: int param[256], params = 0;
4839: memset(param, 0, sizeof(param));
4840: for(int i = 2; i < p; i++) {
4841: if(tmp[i] >= '0' && tmp[i] <= '9') {
4842: param[params] *= 10;
4843: param[params] += tmp[i] - '0';
4844: } else {
4845: params++;
4846: }
4847: }
4848: if(data == 'A') {
1.1.1.14 root 4849: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 4850: } else if(data == 'B') {
1.1.1.14 root 4851: co.Y += (params == 0) ? 1 : param[0];
1.1 root 4852: } else if(data == 'C') {
1.1.1.14 root 4853: co.X += (params == 0) ? 1 : param[0];
1.1 root 4854: } else if(data == 'D') {
1.1.1.14 root 4855: co.X -= (params == 0) ? 1 : param[0];
1.1 root 4856: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 4857: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
4858: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 4859: } else if(data == 'J') {
1.1.1.14 root 4860: clear_scr_buffer(csbi.wAttributes);
1.1 root 4861: if(param[0] == 0) {
4862: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4863: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4864: if(co.Y < csbi.srWindow.Bottom) {
4865: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4866: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4867: }
4868: } else if(param[0] == 1) {
1.1.1.14 root 4869: if(co.Y > csbi.srWindow.Top) {
4870: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
4871: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4872: }
4873: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 4874: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4875: } else if(param[0] == 2) {
1.1.1.14 root 4876: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4877: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4878: co.X = co.Y = 0;
4879: }
4880: } else if(data == 'K') {
1.1.1.14 root 4881: clear_scr_buffer(csbi.wAttributes);
1.1 root 4882: if(param[0] == 0) {
4883: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4884: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4885: } else if(param[0] == 1) {
4886: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 4887: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4888: } else if(param[0] == 2) {
4889: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4890: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4891: }
4892: } else if(data == 'L') {
1.1.1.14 root 4893: if(params == 0) {
4894: param[0] = 1;
1.1 root 4895: }
1.1.1.14 root 4896: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4897: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4898: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4899: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4900: clear_scr_buffer(csbi.wAttributes);
1.1 root 4901: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 4902: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4903: co.X = 0;
4904: } else if(data == 'M') {
1.1.1.14 root 4905: if(params == 0) {
4906: param[0] = 1;
4907: }
4908: if(co.Y + param[0] > csbi.srWindow.Bottom) {
4909: clear_scr_buffer(csbi.wAttributes);
4910: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4911: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4912: } else {
1.1.1.14 root 4913: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4914: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4915: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4916: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4917: clear_scr_buffer(csbi.wAttributes);
1.1 root 4918: }
4919: co.X = 0;
4920: } else if(data == 'h') {
4921: if(tmp[2] == '>' && tmp[3] == '5') {
4922: CONSOLE_CURSOR_INFO cur;
4923: GetConsoleCursorInfo(hStdout, &cur);
4924: if(cur.bVisible) {
4925: cur.bVisible = FALSE;
1.1.1.14 root 4926: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 4927: }
4928: }
4929: } else if(data == 'l') {
4930: if(tmp[2] == '>' && tmp[3] == '5') {
4931: CONSOLE_CURSOR_INFO cur;
4932: GetConsoleCursorInfo(hStdout, &cur);
4933: if(!cur.bVisible) {
4934: cur.bVisible = TRUE;
1.1.1.14 root 4935: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 4936: }
4937: }
4938: } else if(data == 'm') {
4939: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
4940: int reverse = 0, hidden = 0;
4941: for(int i = 0; i < params; i++) {
4942: if(param[i] == 1) {
4943: wAttributes |= FOREGROUND_INTENSITY;
4944: } else if(param[i] == 4) {
4945: wAttributes |= COMMON_LVB_UNDERSCORE;
4946: } else if(param[i] == 7) {
4947: reverse = 1;
4948: } else if(param[i] == 8 || param[i] == 16) {
4949: hidden = 1;
4950: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
4951: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
4952: if(param[i] >= 17 && param[i] <= 23) {
4953: param[i] -= 16;
4954: } else {
4955: param[i] -= 30;
4956: }
4957: if(param[i] & 1) {
4958: wAttributes |= FOREGROUND_RED;
4959: }
4960: if(param[i] & 2) {
4961: wAttributes |= FOREGROUND_GREEN;
4962: }
4963: if(param[i] & 4) {
4964: wAttributes |= FOREGROUND_BLUE;
4965: }
4966: } else if(param[i] >= 40 && param[i] <= 47) {
4967: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
4968: if((param[i] - 40) & 1) {
4969: wAttributes |= BACKGROUND_RED;
4970: }
4971: if((param[i] - 40) & 2) {
4972: wAttributes |= BACKGROUND_GREEN;
4973: }
4974: if((param[i] - 40) & 4) {
4975: wAttributes |= BACKGROUND_BLUE;
4976: }
4977: }
4978: }
4979: if(reverse) {
4980: wAttributes &= ~0xff;
4981: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
4982: }
4983: if(hidden) {
4984: wAttributes &= ~0x0f;
4985: wAttributes |= (wAttributes >> 4) & 0x0f;
4986: }
4987: } else if(data == 'n') {
4988: if(param[0] == 6) {
4989: char tmp[16];
4990: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
4991: int len = strlen(tmp);
1.1.1.32 root 4992: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 4993: #ifdef USE_SERVICE_THREAD
! 4994: EnterCriticalSection(&key_buf_crit_sect);
! 4995: #endif
1.1.1.32 root 4996: for(int i = 0; i < len; i++) {
4997: key_buf_char->write(tmp[i]);
4998: key_buf_scan->write(0x00);
4999: }
1.1.1.35! root 5000: #ifdef USE_SERVICE_THREAD
! 5001: LeaveCriticalSection(&key_buf_crit_sect);
! 5002: #endif
1.1 root 5003: }
5004: }
5005: } else if(data == 's') {
5006: stored_x = co.X;
5007: stored_y = co.Y;
5008: stored_a = wAttributes;
5009: } else if(data == 'u') {
5010: co.X = stored_x;
5011: co.Y = stored_y;
5012: wAttributes = stored_a;
5013: }
5014: }
5015: if(co.X < 0) {
5016: co.X = 0;
5017: } else if(co.X >= csbi.dwSize.X) {
5018: co.X = csbi.dwSize.X - 1;
5019: }
1.1.1.14 root 5020: if(co.Y < csbi.srWindow.Top) {
5021: co.Y = csbi.srWindow.Top;
5022: } else if(co.Y > csbi.srWindow.Bottom) {
5023: co.Y = csbi.srWindow.Bottom;
1.1 root 5024: }
5025: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
5026: SetConsoleCursorPosition(hStdout, co);
5027: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5028: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 5029: cursor_moved = false;
5030: }
5031: if(wAttributes != csbi.wAttributes) {
5032: SetConsoleTextAttribute(hStdout, wAttributes);
5033: }
5034: p = is_esc = 0;
5035: }
5036: return;
5037: } else {
5038: if(msdos_lead_byte_check(data)) {
5039: is_kanji = 1;
5040: return;
5041: } else if(data == 0x1b) {
5042: is_esc = 1;
5043: return;
5044: }
5045: }
1.1.1.20 root 5046:
5047: DWORD q = 0, num;
5048: is_kanji = 0;
5049: for(int i = 0; i < p; i++) {
5050: UINT8 c = tmp[i];
5051: if(is_kanji) {
5052: is_kanji = 0;
5053: } else if(msdos_lead_byte_check(data)) {
5054: is_kanji = 1;
5055: } else if(msdos_ctrl_code_check(data)) {
5056: out[q++] = '^';
5057: c += 'A' - 1;
5058: }
5059: out[q++] = c;
5060: }
1.1.1.34 root 5061: if(q == 1 && out[0] == 0x08) {
5062: // back space
5063: GetConsoleScreenBufferInfo(hStdout, &csbi);
5064: if(csbi.dwCursorPosition.X > 0) {
5065: co.X = csbi.dwCursorPosition.X - 1;
5066: co.Y = csbi.dwCursorPosition.Y;
5067: SetConsoleCursorPosition(hStdout, co);
5068: } else if(csbi.dwCursorPosition.Y > 0) {
5069: co.X = csbi.dwSize.X - 1;
5070: co.Y = csbi.dwCursorPosition.Y - 1;
5071: SetConsoleCursorPosition(hStdout, co);
5072: } else {
5073: WriteConsole(hStdout, out, q, &num, NULL); // to make sure
5074: }
5075: } else {
5076: WriteConsole(hStdout, out, q, &num, NULL);
5077: }
1.1 root 5078: p = 0;
1.1.1.14 root 5079:
1.1.1.15 root 5080: if(!restore_console_on_exit) {
5081: GetConsoleScreenBufferInfo(hStdout, &csbi);
5082: scr_top = csbi.srWindow.Top;
5083: }
1.1 root 5084: cursor_moved = true;
5085: }
5086:
5087: int msdos_aux_in()
5088: {
1.1.1.21 root 5089: msdos_stdio_reopen();
5090:
1.1.1.20 root 5091: process_t *process = msdos_process_info_get(current_psp);
5092: int fd = msdos_psp_get_file_table(3, current_psp);
5093:
5094: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 5095: char data = 0;
1.1.1.20 root 5096: _read(fd, &data, 1);
1.1 root 5097: return(data);
5098: } else {
5099: return(EOF);
5100: }
5101: }
5102:
5103: void msdos_aux_out(char data)
5104: {
1.1.1.21 root 5105: msdos_stdio_reopen();
5106:
1.1.1.20 root 5107: process_t *process = msdos_process_info_get(current_psp);
5108: int fd = msdos_psp_get_file_table(3, current_psp);
5109:
5110: if(fd < process->max_files && file_handler[fd].valid) {
5111: msdos_write(fd, &data, 1);
1.1 root 5112: }
5113: }
5114:
5115: void msdos_prn_out(char data)
5116: {
1.1.1.21 root 5117: msdos_stdio_reopen();
5118:
1.1.1.20 root 5119: process_t *process = msdos_process_info_get(current_psp);
5120: int fd = msdos_psp_get_file_table(4, current_psp);
5121:
5122: if(fd < process->max_files && file_handler[fd].valid) {
5123: msdos_write(fd, &data, 1);
1.1 root 5124: }
5125: }
5126:
5127: // memory control
5128:
1.1.1.19 root 5129: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 5130: {
5131: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5132:
5133: mcb->mz = mz;
5134: mcb->psp = psp;
1.1.1.30 root 5135: mcb->paragraphs = paragraphs;
1.1 root 5136: return(mcb);
5137: }
5138:
5139: void msdos_mcb_check(mcb_t *mcb)
5140: {
5141: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 5142: #if 0
5143: // shutdown now !!!
5144: fatalerror("broken memory control block\n");
5145: #else
5146: // return error code and continue
5147: throw(0x07); // broken memory control block
5148: #endif
1.1 root 5149: }
5150: }
5151:
5152: int msdos_mem_split(int seg, int paragraphs)
5153: {
5154: int mcb_seg = seg - 1;
5155: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5156: msdos_mcb_check(mcb);
5157:
1.1.1.30 root 5158: if(mcb->paragraphs > paragraphs) {
1.1 root 5159: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 5160: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 5161:
5162: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5163: mcb->mz = 'M';
1.1.1.30 root 5164: mcb->paragraphs = paragraphs;
1.1 root 5165: return(0);
5166: }
5167: return(-1);
5168: }
5169:
5170: void msdos_mem_merge(int seg)
5171: {
5172: int mcb_seg = seg - 1;
5173: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5174: msdos_mcb_check(mcb);
5175:
5176: while(1) {
5177: if(mcb->mz == 'Z') {
5178: break;
5179: }
1.1.1.30 root 5180: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 5181: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5182: msdos_mcb_check(next_mcb);
5183:
5184: if(next_mcb->psp != 0) {
5185: break;
5186: }
5187: mcb->mz = next_mcb->mz;
1.1.1.30 root 5188: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 5189: }
5190: }
5191:
1.1.1.8 root 5192: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 5193: {
5194: while(1) {
5195: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5196: bool last_block;
1.1 root 5197:
1.1.1.14 root 5198: if(mcb->psp == 0) {
5199: msdos_mem_merge(mcb_seg + 1);
5200: } else {
5201: msdos_mcb_check(mcb);
5202: }
1.1.1.33 root 5203: if(!(last_block = (mcb->mz == 'Z'))) {
5204: // check if the next is dummy mcb to link to umb
5205: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5206: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5207: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5208: }
5209: if(!(new_process && !last_block)) {
1.1.1.30 root 5210: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 5211: msdos_mem_split(mcb_seg + 1, paragraphs);
5212: mcb->psp = current_psp;
5213: return(mcb_seg + 1);
5214: }
5215: }
5216: if(mcb->mz == 'Z') {
5217: break;
5218: }
1.1.1.30 root 5219: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5220: }
5221: return(-1);
5222: }
5223:
5224: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5225: {
5226: int mcb_seg = seg - 1;
5227: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5228: msdos_mcb_check(mcb);
1.1.1.30 root 5229: int current_paragraphs = mcb->paragraphs;
1.1 root 5230:
5231: msdos_mem_merge(seg);
1.1.1.30 root 5232: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 5233: if(max_paragraphs) {
1.1.1.30 root 5234: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 5235: }
1.1 root 5236: msdos_mem_split(seg, current_paragraphs);
5237: return(-1);
5238: }
5239: msdos_mem_split(seg, paragraphs);
5240: return(0);
5241: }
5242:
5243: void msdos_mem_free(int seg)
5244: {
5245: int mcb_seg = seg - 1;
5246: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5247: msdos_mcb_check(mcb);
5248:
5249: mcb->psp = 0;
5250: msdos_mem_merge(seg);
5251: }
5252:
1.1.1.8 root 5253: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 5254: {
5255: int max_paragraphs = 0;
5256:
5257: while(1) {
5258: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5259: bool last_block;
5260:
1.1 root 5261: msdos_mcb_check(mcb);
5262:
1.1.1.33 root 5263: if(!(last_block = (mcb->mz == 'Z'))) {
5264: // check if the next is dummy mcb to link to umb
5265: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5266: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5267: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5268: }
5269: if(!(new_process && !last_block)) {
1.1.1.30 root 5270: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
5271: max_paragraphs = mcb->paragraphs;
1.1 root 5272: }
5273: }
5274: if(mcb->mz == 'Z') {
5275: break;
5276: }
1.1.1.30 root 5277: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5278: }
1.1.1.14 root 5279: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 5280: }
5281:
1.1.1.8 root 5282: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
5283: {
5284: int last_seg = -1;
5285:
5286: while(1) {
5287: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5288: msdos_mcb_check(mcb);
5289:
1.1.1.14 root 5290: if(mcb->psp == psp) {
1.1.1.8 root 5291: last_seg = mcb_seg;
5292: }
1.1.1.14 root 5293: if(mcb->mz == 'Z') {
5294: break;
5295: }
1.1.1.30 root 5296: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 5297: }
5298: return(last_seg);
5299: }
5300:
1.1.1.19 root 5301: int msdos_mem_get_umb_linked()
5302: {
1.1.1.33 root 5303: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5304: msdos_mcb_check(mcb);
1.1.1.19 root 5305:
1.1.1.33 root 5306: if(mcb->mz == 'M') {
5307: return(-1);
1.1.1.19 root 5308: }
5309: return(0);
5310: }
5311:
1.1.1.33 root 5312: void msdos_mem_link_umb()
1.1.1.19 root 5313: {
1.1.1.33 root 5314: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5315: msdos_mcb_check(mcb);
1.1.1.19 root 5316:
1.1.1.33 root 5317: mcb->mz = 'M';
5318: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
1.1.1.19 root 5319: }
5320:
1.1.1.33 root 5321: void msdos_mem_unlink_umb()
1.1.1.19 root 5322: {
1.1.1.33 root 5323: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5324: msdos_mcb_check(mcb);
1.1.1.19 root 5325:
1.1.1.33 root 5326: mcb->mz = 'Z';
5327: mcb->paragraphs = 0;
1.1.1.19 root 5328: }
5329:
1.1.1.29 root 5330: #ifdef SUPPORT_HMA
5331:
5332: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
5333: {
5334: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5335:
5336: mcb->ms[0] = 'M';
5337: mcb->ms[1] = 'S';
5338: mcb->owner = owner;
5339: mcb->size = size;
5340: mcb->next = next;
5341: return(mcb);
5342: }
5343:
5344: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
5345: {
5346: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
5347: }
5348:
5349: int msdos_hma_mem_split(int offset, int size)
5350: {
5351: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5352:
5353: if(!msdos_is_hma_mcb_valid(mcb)) {
5354: return(-1);
5355: }
5356: if(mcb->size >= size + 0x10) {
5357: int new_offset = offset + 0x10 + size;
5358: int new_size = mcb->size - 0x10 - size;
5359:
5360: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
5361: mcb->size = size;
5362: mcb->next = new_offset;
5363: return(0);
5364: }
5365: return(-1);
5366: }
5367:
5368: void msdos_hma_mem_merge(int offset)
5369: {
5370: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5371:
5372: if(!msdos_is_hma_mcb_valid(mcb)) {
5373: return;
5374: }
5375: while(1) {
5376: if(mcb->next == 0) {
5377: break;
5378: }
5379: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
5380:
5381: if(!msdos_is_hma_mcb_valid(next_mcb)) {
5382: return;
5383: }
5384: if(next_mcb->owner != 0) {
5385: break;
5386: }
5387: mcb->size += 0x10 + next_mcb->size;
5388: mcb->next = next_mcb->next;
5389: }
5390: }
5391:
5392: int msdos_hma_mem_alloc(int size, UINT16 owner)
5393: {
5394: int offset = 0x10; // first mcb in HMA
5395:
5396: while(1) {
5397: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5398:
5399: if(!msdos_is_hma_mcb_valid(mcb)) {
5400: return(-1);
5401: }
5402: if(mcb->owner == 0) {
5403: msdos_hma_mem_merge(offset);
5404: }
5405: if(mcb->owner == 0 && mcb->size >= size) {
5406: msdos_hma_mem_split(offset, size);
5407: mcb->owner = owner;
5408: return(offset);
5409: }
5410: if(mcb->next == 0) {
5411: break;
5412: }
5413: offset = mcb->next;
5414: }
5415: return(-1);
5416: }
5417:
5418: int msdos_hma_mem_realloc(int offset, int size)
5419: {
5420: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5421:
5422: if(!msdos_is_hma_mcb_valid(mcb)) {
5423: return(-1);
5424: }
5425: if(mcb->size < size) {
5426: return(-1);
5427: }
5428: msdos_hma_mem_split(offset, size);
5429: return(0);
5430: }
5431:
5432: void msdos_hma_mem_free(int offset)
5433: {
5434: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5435:
5436: if(!msdos_is_hma_mcb_valid(mcb)) {
5437: return;
5438: }
5439: mcb->owner = 0;
5440: msdos_hma_mem_merge(offset);
5441: }
5442:
5443: int msdos_hma_mem_get_free(int *available_offset)
5444: {
5445: int offset = 0x10; // first mcb in HMA
5446: int size = 0;
5447:
5448: while(1) {
5449: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5450:
5451: if(!msdos_is_hma_mcb_valid(mcb)) {
5452: return(0);
5453: }
5454: if(mcb->owner == 0 && size < mcb->size) {
5455: if(available_offset != NULL) {
5456: *available_offset = offset;
5457: }
5458: size = mcb->size;
5459: }
5460: if(mcb->next == 0) {
5461: break;
5462: }
5463: offset = mcb->next;
5464: }
5465: return(size);
5466: }
5467:
5468: #endif
5469:
1.1 root 5470: // environment
5471:
5472: void msdos_env_set_argv(int env_seg, char *argv)
5473: {
5474: char *dst = (char *)(mem + (env_seg << 4));
5475:
5476: while(1) {
5477: if(dst[0] == 0) {
5478: break;
5479: }
5480: dst += strlen(dst) + 1;
5481: }
5482: *dst++ = 0; // end of environment
5483: *dst++ = 1; // top of argv[0]
5484: *dst++ = 0;
5485: memcpy(dst, argv, strlen(argv));
5486: dst += strlen(argv);
5487: *dst++ = 0;
5488: *dst++ = 0;
5489: }
5490:
5491: char *msdos_env_get_argv(int env_seg)
5492: {
5493: static char env[ENV_SIZE];
5494: char *src = env;
5495:
5496: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5497: while(1) {
5498: if(src[0] == 0) {
5499: if(src[1] == 1) {
5500: return(src + 3);
5501: }
5502: break;
5503: }
5504: src += strlen(src) + 1;
5505: }
5506: return(NULL);
5507: }
5508:
5509: char *msdos_env_get(int env_seg, const char *name)
5510: {
5511: static char env[ENV_SIZE];
5512: char *src = env;
5513:
5514: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5515: while(1) {
5516: if(src[0] == 0) {
5517: break;
5518: }
5519: int len = strlen(src);
5520: char *n = my_strtok(src, "=");
5521: char *v = src + strlen(n) + 1;
5522:
5523: if(_stricmp(name, n) == 0) {
5524: return(v);
5525: }
5526: src += len + 1;
5527: }
5528: return(NULL);
5529: }
5530:
5531: void msdos_env_set(int env_seg, char *name, char *value)
5532: {
5533: char env[ENV_SIZE];
5534: char *src = env;
5535: char *dst = (char *)(mem + (env_seg << 4));
5536: char *argv = msdos_env_get_argv(env_seg);
5537: int done = 0;
5538:
5539: memcpy(src, dst, ENV_SIZE);
5540: memset(dst, 0, ENV_SIZE);
5541: while(1) {
5542: if(src[0] == 0) {
5543: break;
5544: }
5545: int len = strlen(src);
5546: char *n = my_strtok(src, "=");
5547: char *v = src + strlen(n) + 1;
5548: char tmp[1024];
5549:
5550: if(_stricmp(name, n) == 0) {
5551: sprintf(tmp, "%s=%s", n, value);
5552: done = 1;
5553: } else {
5554: sprintf(tmp, "%s=%s", n, v);
5555: }
5556: memcpy(dst, tmp, strlen(tmp));
5557: dst += strlen(tmp) + 1;
5558: src += len + 1;
5559: }
5560: if(!done) {
5561: char tmp[1024];
5562:
5563: sprintf(tmp, "%s=%s", name, value);
5564: memcpy(dst, tmp, strlen(tmp));
5565: dst += strlen(tmp) + 1;
5566: }
5567: if(argv) {
5568: *dst++ = 0; // end of environment
5569: *dst++ = 1; // top of argv[0]
5570: *dst++ = 0;
5571: memcpy(dst, argv, strlen(argv));
5572: dst += strlen(argv);
5573: *dst++ = 0;
5574: *dst++ = 0;
5575: }
5576: }
5577:
5578: // process
5579:
1.1.1.8 root 5580: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 5581: {
5582: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5583:
5584: memset(psp, 0, PSP_SIZE);
5585: psp->exit[0] = 0xcd;
5586: psp->exit[1] = 0x20;
1.1.1.8 root 5587: psp->first_mcb = mcb_seg;
1.1 root 5588: psp->far_call = 0xea;
5589: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
5590: psp->cpm_entry.w.h = 0xf000;
5591: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5592: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5593: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5594: psp->parent_psp = parent_psp;
1.1.1.20 root 5595: if(parent_psp == (UINT16)-1) {
5596: for(int i = 0; i < 20; i++) {
5597: if(file_handler[i].valid) {
5598: psp->file_table[i] = i;
5599: } else {
5600: psp->file_table[i] = 0xff;
5601: }
1.1 root 5602: }
1.1.1.20 root 5603: } else {
5604: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 5605: }
5606: psp->env_seg = env_seg;
5607: psp->stack.w.l = REG16(SP);
1.1.1.3 root 5608: psp->stack.w.h = SREG(SS);
1.1.1.14 root 5609: psp->file_table_size = 20;
5610: psp->file_table_ptr.w.l = 0x18;
5611: psp->file_table_ptr.w.h = psp_seg;
1.1 root 5612: psp->service[0] = 0xcd;
5613: psp->service[1] = 0x21;
5614: psp->service[2] = 0xcb;
5615: return(psp);
5616: }
5617:
1.1.1.20 root 5618: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
5619: {
5620: if(psp_seg && fd < 20) {
5621: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5622: psp->file_table[fd] = value;
5623: }
5624: }
5625:
5626: int msdos_psp_get_file_table(int fd, int psp_seg)
5627: {
5628: if(psp_seg && fd < 20) {
5629: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5630: fd = psp->file_table[fd];
5631: }
5632: return fd;
5633: }
5634:
1.1 root 5635: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
5636: {
5637: // load command file
5638: int fd = -1;
5639: int dos_command = 0;
1.1.1.24 root 5640: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 5641:
5642: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5643: int opt_len = mem[opt_ofs];
5644: memset(opt, 0, sizeof(opt));
5645: memcpy(opt, mem + opt_ofs + 1, opt_len);
5646:
1.1.1.14 root 5647: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
5648: // this is a batch file, run command.com
5649: char tmp[MAX_PATH];
5650: if(opt_len != 0) {
5651: sprintf(tmp, "/C %s %s", cmd, opt);
5652: } else {
5653: sprintf(tmp, "/C %s", cmd);
5654: }
5655: strcpy(opt, tmp);
5656: opt_len = strlen(opt);
5657: mem[opt_ofs] = opt_len;
5658: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5659: strcpy(command, comspec_path);
5660: strcpy(name_tmp, "COMMAND.COM");
5661: } else {
5662: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
5663: // redirect C:\COMMAND.COM to comspec_path
5664: strcpy(command, comspec_path);
5665: } else {
5666: strcpy(command, cmd);
5667: }
1.1.1.24 root 5668: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
5669: return(-1);
5670: }
1.1.1.14 root 5671: memset(name_tmp, 0, sizeof(name_tmp));
5672: strcpy(name_tmp, name);
5673:
5674: // check command.com
5675: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
5676: if(opt_len == 0) {
5677: // process_t *current_process = msdos_process_info_get(current_psp);
5678: process_t *current_process = NULL;
5679: for(int i = 0; i < MAX_PROCESS; i++) {
5680: if(process[i].psp == current_psp) {
5681: current_process = &process[i];
5682: break;
5683: }
5684: }
5685: if(current_process != NULL) {
5686: param->cmd_line.dw = current_process->dta.dw;
5687: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5688: opt_len = mem[opt_ofs];
5689: memset(opt, 0, sizeof(opt));
5690: memcpy(opt, mem + opt_ofs + 1, opt_len);
5691: }
5692: }
5693: for(int i = 0; i < opt_len; i++) {
5694: if(opt[i] == ' ') {
5695: continue;
5696: }
5697: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
5698: for(int j = i + 3; j < opt_len; j++) {
5699: if(opt[j] == ' ') {
5700: continue;
5701: }
5702: char *token = my_strtok(opt + j, " ");
5703:
5704: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
5705: // this is a batch file, okay to run command.com
5706: } else {
5707: // run program directly without command.com
5708: strcpy(command, token);
5709: char tmp[MAX_PATH];
5710: strcpy(tmp, token + strlen(token) + 1);
5711: strcpy(opt, tmp);
5712: opt_len = strlen(opt);
5713: mem[opt_ofs] = opt_len;
5714: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5715: dos_command = 1;
5716: }
5717: break;
1.1 root 5718: }
5719: }
1.1.1.14 root 5720: break;
1.1 root 5721: }
5722: }
5723: }
5724:
5725: // load command file
5726: strcpy(path, command);
5727: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5728: sprintf(path, "%s.COM", command);
5729: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5730: sprintf(path, "%s.EXE", command);
5731: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 5732: sprintf(path, "%s.BAT", command);
5733: if(_access(path, 0) == 0) {
5734: // this is a batch file, run command.com
5735: char tmp[MAX_PATH];
5736: if(opt_len != 0) {
5737: sprintf(tmp, "/C %s %s", path, opt);
5738: } else {
5739: sprintf(tmp, "/C %s", path);
5740: }
5741: strcpy(opt, tmp);
5742: opt_len = strlen(opt);
5743: mem[opt_ofs] = opt_len;
5744: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5745: strcpy(path, comspec_path);
5746: strcpy(name_tmp, "COMMAND.COM");
5747: fd = _open(path, _O_RDONLY | _O_BINARY);
5748: } else {
5749: // search path in parent environments
5750: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5751: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
5752: if(env != NULL) {
5753: char env_path[4096];
5754: strcpy(env_path, env);
5755: char *token = my_strtok(env_path, ";");
5756:
5757: while(token != NULL) {
5758: if(strlen(token) != 0) {
5759: sprintf(path, "%s", msdos_combine_path(token, command));
5760: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5761: break;
5762: }
5763: sprintf(path, "%s.COM", msdos_combine_path(token, command));
5764: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5765: break;
5766: }
5767: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
5768: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5769: break;
5770: }
5771: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
5772: if(_access(path, 0) == 0) {
5773: // this is a batch file, run command.com
5774: char tmp[MAX_PATH];
5775: if(opt_len != 0) {
5776: sprintf(tmp, "/C %s %s", path, opt);
5777: } else {
5778: sprintf(tmp, "/C %s", path);
5779: }
5780: strcpy(opt, tmp);
5781: opt_len = strlen(opt);
5782: mem[opt_ofs] = opt_len;
5783: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5784: strcpy(path, comspec_path);
5785: strcpy(name_tmp, "COMMAND.COM");
5786: fd = _open(path, _O_RDONLY | _O_BINARY);
5787: break;
5788: }
1.1.1.8 root 5789: }
1.1.1.14 root 5790: token = my_strtok(NULL, ";");
1.1 root 5791: }
5792: }
5793: }
5794: }
5795: }
5796: }
5797: if(fd == -1) {
5798: if(dos_command) {
5799: // may be dos command
5800: char tmp[MAX_PATH];
5801: sprintf(tmp, "%s %s", command, opt);
5802: system(tmp);
5803: return(0);
5804: } else {
5805: return(-1);
5806: }
5807: }
5808: _read(fd, file_buffer, sizeof(file_buffer));
5809: _close(fd);
5810:
5811: // copy environment
1.1.1.29 root 5812: int umb_linked, env_seg, psp_seg;
1.1 root 5813:
1.1.1.29 root 5814: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
5815: msdos_mem_unlink_umb();
5816: }
1.1.1.8 root 5817: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 5818: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
5819: if(umb_linked != 0) {
5820: msdos_mem_link_umb();
5821: }
5822: return(-1);
5823: }
1.1 root 5824: }
5825: if(param->env_seg == 0) {
5826: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5827: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
5828: } else {
5829: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
5830: }
5831: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
5832:
5833: // check exe header
5834: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 5835: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 5836: UINT16 cs, ss, ip, sp;
5837:
5838: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
5839: // memory allocation
5840: int header_size = header->header_size * 16;
5841: int load_size = header->pages * 512 - header_size;
5842: if(header_size + load_size < 512) {
5843: load_size = 512 - header_size;
5844: }
5845: paragraphs = (PSP_SIZE + load_size) >> 4;
5846: if(paragraphs + header->min_alloc > free_paragraphs) {
5847: msdos_mem_free(env_seg);
5848: return(-1);
5849: }
5850: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
5851: if(paragraphs > free_paragraphs) {
5852: paragraphs = free_paragraphs;
5853: }
1.1.1.8 root 5854: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 5855: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
5856: if(umb_linked != 0) {
5857: msdos_mem_link_umb();
5858: }
5859: msdos_mem_free(env_seg);
5860: return(-1);
5861: }
1.1 root 5862: }
5863: // relocation
5864: int start_seg = psp_seg + (PSP_SIZE >> 4);
5865: for(int i = 0; i < header->relocations; i++) {
5866: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
5867: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
5868: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
5869: }
5870: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
5871: // segments
5872: cs = header->init_cs + start_seg;
5873: ss = header->init_ss + start_seg;
5874: ip = header->init_ip;
5875: sp = header->init_sp - 2; // for symdeb
5876: } else {
5877: // memory allocation
5878: paragraphs = free_paragraphs;
1.1.1.8 root 5879: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 5880: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
5881: if(umb_linked != 0) {
5882: msdos_mem_link_umb();
5883: }
5884: msdos_mem_free(env_seg);
5885: return(-1);
5886: }
1.1 root 5887: }
5888: int start_seg = psp_seg + (PSP_SIZE >> 4);
5889: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
5890: // segments
5891: cs = ss = psp_seg;
5892: ip = 0x100;
5893: sp = 0xfffe;
5894: }
1.1.1.29 root 5895: if(umb_linked != 0) {
5896: msdos_mem_link_umb();
5897: }
1.1 root 5898:
5899: // create psp
1.1.1.3 root 5900: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
5901: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 5902: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
5903: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
5904: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
5905: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
5906:
5907: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
5908: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
5909: mcb_psp->psp = mcb_env->psp = psp_seg;
5910:
1.1.1.4 root 5911: for(int i = 0; i < 8; i++) {
5912: if(name_tmp[i] == '.') {
5913: mcb_psp->prog_name[i] = '\0';
5914: break;
5915: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
5916: mcb_psp->prog_name[i] = name_tmp[i];
5917: i++;
5918: mcb_psp->prog_name[i] = name_tmp[i];
5919: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
5920: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
5921: } else {
5922: mcb_psp->prog_name[i] = name_tmp[i];
5923: }
5924: }
5925:
1.1 root 5926: // process info
5927: process_t *process = msdos_process_info_create(psp_seg);
5928: strcpy(process->module_dir, msdos_short_full_dir(path));
1.1.1.33 root 5929: #ifdef USE_DEBUGGER
5930: strcpy(process->module_path, path);
5931: #endif
1.1 root 5932: process->dta.w.l = 0x80;
5933: process->dta.w.h = psp_seg;
5934: process->switchar = '/';
5935: process->max_files = 20;
5936: process->parent_int_10h_feh_called = int_10h_feh_called;
5937: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 5938: process->parent_ds = SREG(DS);
1.1.1.31 root 5939: process->parent_es = SREG(ES);
1.1 root 5940:
5941: current_psp = psp_seg;
1.1.1.23 root 5942: msdos_sda_update(current_psp);
1.1 root 5943:
5944: if(al == 0x00) {
5945: int_10h_feh_called = int_10h_ffh_called = false;
5946:
5947: // registers and segments
5948: REG16(AX) = REG16(BX) = 0x00;
5949: REG16(CX) = 0xff;
5950: REG16(DX) = psp_seg;
5951: REG16(SI) = ip;
5952: REG16(DI) = sp;
5953: REG16(SP) = sp;
1.1.1.3 root 5954: SREG(DS) = SREG(ES) = psp_seg;
5955: SREG(SS) = ss;
5956: i386_load_segment_descriptor(DS);
5957: i386_load_segment_descriptor(ES);
5958: i386_load_segment_descriptor(SS);
1.1 root 5959:
5960: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
5961: i386_jmp_far(cs, ip);
5962: } else if(al == 0x01) {
5963: // copy ss:sp and cs:ip to param block
5964: param->sp = sp;
5965: param->ss = ss;
5966: param->ip = ip;
5967: param->cs = cs;
1.1.1.31 root 5968:
5969: // the AX value to be passed to the child program is put on top of the child's stack
5970: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 5971: }
5972: return(0);
5973: }
5974:
5975: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
5976: {
5977: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5978:
5979: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
5980: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
5981: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
5982:
1.1.1.3 root 5983: SREG(SS) = psp->stack.w.h;
5984: i386_load_segment_descriptor(SS);
1.1 root 5985: REG16(SP) = psp->stack.w.l;
5986: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
5987:
1.1.1.28 root 5988: // process_t *current_process = msdos_process_info_get(psp_seg);
5989: process_t *current_process = NULL;
5990: for(int i = 0; i < MAX_PROCESS; i++) {
5991: if(process[i].psp == psp_seg) {
5992: current_process = &process[i];
5993: break;
5994: }
5995: }
5996: if(current_process == NULL) {
5997: throw(0x1f); // general failure
5998: }
5999: int_10h_feh_called = current_process->parent_int_10h_feh_called;
6000: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
6001: if(current_process->called_by_int2eh) {
6002: REG16(AX) = ret;
6003: }
6004: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 6005: SREG(ES) = current_process->parent_es;
1.1.1.14 root 6006: i386_load_segment_descriptor(DS);
1.1.1.31 root 6007: i386_load_segment_descriptor(ES);
1.1 root 6008:
6009: if(mem_free) {
1.1.1.8 root 6010: int mcb_seg;
6011: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
6012: msdos_mem_free(mcb_seg + 1);
6013: }
6014: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
6015: msdos_mem_free(mcb_seg + 1);
6016: }
1.1 root 6017:
6018: for(int i = 0; i < MAX_FILES; i++) {
6019: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
6020: _close(i);
1.1.1.20 root 6021: msdos_file_handler_close(i);
6022: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 6023: }
6024: }
1.1.1.13 root 6025: msdos_dta_info_free(psp_seg);
1.1 root 6026: }
1.1.1.14 root 6027: msdos_stdio_reopen();
1.1 root 6028:
1.1.1.28 root 6029: memset(current_process, 0, sizeof(process_t));
1.1 root 6030:
6031: current_psp = psp->parent_psp;
6032: retval = ret;
1.1.1.23 root 6033: msdos_sda_update(current_psp);
1.1 root 6034: }
6035:
6036: // drive
6037:
6038: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
6039: {
6040: *seg = DPB_TOP >> 4;
6041: *ofs = sizeof(dpb_t) * drive_num;
6042: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
6043:
6044: if(!force_update && dpb->free_clusters != 0) {
6045: return(dpb->bytes_per_sector ? 1 : 0);
6046: }
6047: memset(dpb, 0, sizeof(dpb_t));
6048:
6049: int res = 0;
6050: char dev[64];
6051: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
6052:
1.1.1.17 root 6053: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 6054: if(hFile != INVALID_HANDLE_VALUE) {
6055: DISK_GEOMETRY geo;
6056: DWORD dwSize;
6057: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6058: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
6059: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
6060: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 6061: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 6062: switch(geo.MediaType) {
6063: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6064: dpb->media_type = 0xff;
6065: break;
6066: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6067: dpb->media_type = 0xfe;
6068: break;
6069: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6070: dpb->media_type = 0xfd;
6071: break;
6072: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6073: dpb->media_type = 0xfc;
6074: break;
6075: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6076: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6077: dpb->media_type = 0xf9;
6078: break;
6079: case FixedMedia: // hard disk
6080: case RemovableMedia:
1.1.1.19 root 6081: case Unknown:
1.1 root 6082: dpb->media_type = 0xf8;
6083: break;
6084: default:
6085: dpb->media_type = 0xf0;
6086: break;
6087: }
6088: res = 1;
6089: }
6090: dpb->drive_num = drive_num;
6091: dpb->unit_num = drive_num;
6092: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
6093: dpb->next_dpb_seg = *seg;
1.1.1.14 root 6094: dpb->info_sector = 0xffff;
6095: dpb->backup_boot_sector = 0xffff;
1.1 root 6096: dpb->free_clusters = 0xffff;
1.1.1.14 root 6097: dpb->free_search_cluster = 0xffffffff;
1.1 root 6098: CloseHandle(hFile);
6099: }
6100: return(res);
6101: }
6102:
6103: // pc bios
6104:
1.1.1.35! root 6105: #ifdef USE_SERVICE_THREAD
! 6106: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress)
! 6107: {
! 6108: #if defined(HAS_I386)
! 6109: if(m_SF != 0) {
! 6110: m_SF = 0;
! 6111: mem[0xfffd0 + 0x15] = 0x79; // jns -4
! 6112: } else {
! 6113: m_SF = 1;
! 6114: mem[0xfffd0 + 0x15] = 0x78; // js -4
! 6115: }
! 6116: #else
! 6117: if(m_SignVal < 0) {
! 6118: m_SignVal = 0;
! 6119: mem[0xfffd0 + 0x15] = 0x79; // jns -4
! 6120: } else {
! 6121: m_SignVal = -1;
! 6122: mem[0xfffd0 + 0x15] = 0x78; // js -4
! 6123: }
! 6124: #endif
! 6125: i386_call_far(0xfffd, 0x0013);
! 6126: in_service = true;
! 6127: service_exit = false;
! 6128: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL));
! 6129: }
! 6130:
! 6131: void finish_service_loop()
! 6132: {
! 6133: if(in_service && service_exit) {
! 6134: #if defined(HAS_I386)
! 6135: if(m_SF != 0) {
! 6136: m_SF = 0;
! 6137: } else {
! 6138: m_SF = 1;
! 6139: }
! 6140: #else
! 6141: if(m_SignVal < 0) {
! 6142: m_SignVal = 0;
! 6143: } else {
! 6144: m_SignVal = -1;
! 6145: }
! 6146: #endif
! 6147: in_service = false;
! 6148: }
! 6149: }
! 6150: #endif
! 6151:
1.1.1.19 root 6152: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
6153: {
6154: static unsigned __int64 start_msec_since_midnight = 0;
6155: static unsigned __int64 start_msec_since_hostboot = 0;
6156:
6157: if(start_msec_since_midnight == 0) {
6158: SYSTEMTIME time;
6159: GetLocalTime(&time);
6160: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
6161: start_msec_since_hostboot = cur_msec;
6162: }
6163: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
6164: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
6165: return (UINT32)tick;
6166: }
6167:
6168: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
6169: {
6170: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
6171: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
6172:
6173: if(prev_tick > next_tick) {
6174: mem[0x470] = 1;
6175: }
6176: *(UINT32 *)(mem + 0x46c) = next_tick;
6177: }
6178:
1.1.1.14 root 6179: inline void pcbios_irq0()
6180: {
6181: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 6182: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 6183: }
6184:
1.1.1.16 root 6185: int pcbios_get_text_vram_address(int page)
1.1 root 6186: {
6187: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6188: return TEXT_VRAM_TOP;
1.1 root 6189: } else {
1.1.1.14 root 6190: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 6191: }
6192: }
6193:
1.1.1.16 root 6194: int pcbios_get_shadow_buffer_address(int page)
1.1 root 6195: {
1.1.1.14 root 6196: if(!int_10h_feh_called) {
1.1.1.16 root 6197: return pcbios_get_text_vram_address(page);
1.1.1.14 root 6198: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6199: return SHADOW_BUF_TOP;
6200: } else {
1.1.1.14 root 6201: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 6202: }
6203: }
6204:
1.1.1.16 root 6205: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 6206: {
1.1.1.16 root 6207: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 6208: }
6209:
1.1.1.16 root 6210: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 6211: {
1.1.1.14 root 6212: // clear the existing screen, not just the new one
6213: int clr_height = max(height, scr_height);
6214:
1.1.1.16 root 6215: if(scr_width != width || scr_height != height) {
6216: change_console_size(width, height);
1.1.1.14 root 6217: }
6218: mem[0x462] = 0;
6219: *(UINT16 *)(mem + 0x44e) = 0;
6220:
1.1.1.16 root 6221: text_vram_top_address = pcbios_get_text_vram_address(0);
6222: text_vram_end_address = text_vram_top_address + width * height * 2;
6223: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
6224: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 6225:
1.1.1.23 root 6226: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 6227: if(clr_screen) {
1.1.1.14 root 6228: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
6229: mem[ofs++] = 0x20;
6230: mem[ofs++] = 0x07;
6231: }
6232:
1.1.1.35! root 6233: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6234: EnterCriticalSection(&vram_crit_sect);
1.1.1.35! root 6235: #endif
1.1.1.14 root 6236: for(int y = 0; y < clr_height; y++) {
6237: for(int x = 0; x < scr_width; x++) {
6238: SCR_BUF(y,x).Char.AsciiChar = ' ';
6239: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 6240: }
6241: }
6242: SMALL_RECT rect;
1.1.1.14 root 6243: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
6244: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6245: vram_length_char = vram_last_length_char = 0;
6246: vram_length_attr = vram_last_length_attr = 0;
1.1.1.35! root 6247: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6248: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35! root 6249: #endif
1.1 root 6250: }
1.1.1.14 root 6251: COORD co;
6252: co.X = 0;
6253: co.Y = scr_top;
6254: SetConsoleCursorPosition(hStdout, co);
6255: cursor_moved = true;
6256: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 6257: }
6258:
1.1.1.16 root 6259: inline void pcbios_int_10h_00h()
6260: {
6261: switch(REG8(AL) & 0x7f) {
6262: case 0x70: // v-text mode
6263: case 0x71: // extended cga v-text mode
6264: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
6265: break;
6266: default:
6267: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
6268: break;
6269: }
6270: if(REG8(AL) & 0x80) {
6271: mem[0x487] |= 0x80;
6272: } else {
6273: mem[0x487] &= ~0x80;
6274: }
6275: mem[0x449] = REG8(AL) & 0x7f;
6276: }
6277:
1.1 root 6278: inline void pcbios_int_10h_01h()
6279: {
1.1.1.13 root 6280: mem[0x460] = REG8(CL);
6281: mem[0x461] = REG8(CH);
1.1.1.14 root 6282:
1.1.1.23 root 6283: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6284: CONSOLE_CURSOR_INFO ci;
6285: GetConsoleCursorInfo(hStdout, &ci);
6286: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
6287: // if(ci.bVisible) {
6288: int lines = max(8, REG8(CL) + 1);
6289: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
6290: // }
6291: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 6292: }
6293:
6294: inline void pcbios_int_10h_02h()
6295: {
1.1.1.14 root 6296: // continuously setting the cursor effectively stops it blinking
6297: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 6298: COORD co;
6299: co.X = REG8(DL);
1.1.1.14 root 6300: co.Y = REG8(DH) + scr_top;
6301:
6302: // some programs hide the cursor by moving it off screen
6303: static bool hidden = false;
1.1.1.23 root 6304: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6305: CONSOLE_CURSOR_INFO ci;
6306: GetConsoleCursorInfo(hStdout, &ci);
6307:
6308: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
6309: if(ci.bVisible) {
6310: ci.bVisible = FALSE;
6311: // SetConsoleCursorInfo(hStdout, &ci);
6312: hidden = true;
6313: }
6314: } else if(hidden) {
6315: if(!ci.bVisible) {
6316: ci.bVisible = TRUE;
6317: // SetConsoleCursorInfo(hStdout, &ci);
6318: }
6319: hidden = false;
6320: }
1.1 root 6321: }
1.1.1.14 root 6322: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
6323: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 6324: }
6325:
6326: inline void pcbios_int_10h_03h()
6327: {
1.1.1.14 root 6328: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6329: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6330: REG8(CL) = mem[0x460];
6331: REG8(CH) = mem[0x461];
6332: }
6333:
6334: inline void pcbios_int_10h_05h()
6335: {
1.1.1.14 root 6336: if(REG8(AL) >= vram_pages) {
6337: return;
6338: }
6339: if(mem[0x462] != REG8(AL)) {
6340: vram_flush();
6341:
1.1.1.23 root 6342: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6343: SMALL_RECT rect;
1.1.1.14 root 6344: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6345: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6346:
1.1.1.16 root 6347: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 6348: for(int x = 0; x < scr_width; x++) {
6349: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6350: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6351: }
6352: }
1.1.1.16 root 6353: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 6354: for(int x = 0; x < scr_width; x++) {
6355: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
6356: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 6357: }
6358: }
1.1.1.14 root 6359: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6360:
6361: COORD co;
1.1.1.14 root 6362: co.X = mem[0x450 + REG8(AL) * 2];
6363: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
6364: if(co.Y < scr_top + scr_height) {
6365: SetConsoleCursorPosition(hStdout, co);
6366: }
1.1 root 6367: }
1.1.1.14 root 6368: mem[0x462] = REG8(AL);
6369: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
6370: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 6371: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 6372: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 6373: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 6374: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 6375: }
6376:
6377: inline void pcbios_int_10h_06h()
6378: {
1.1.1.14 root 6379: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6380: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6381: return;
6382: }
6383: vram_flush();
6384:
1.1.1.23 root 6385: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6386: SMALL_RECT rect;
1.1.1.14 root 6387: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6388: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6389:
6390: int right = min(REG8(DL), scr_width - 1);
6391: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6392:
6393: if(REG8(AL) == 0) {
1.1.1.14 root 6394: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6395: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6396: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6397: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6398: }
6399: }
6400: } else {
1.1.1.14 root 6401: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 6402: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6403: if(y2 <= bottom) {
6404: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6405: } else {
1.1.1.14 root 6406: SCR_BUF(y,x).Char.AsciiChar = ' ';
6407: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6408: }
1.1.1.14 root 6409: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6410: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6411: }
6412: }
6413: }
1.1.1.14 root 6414: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6415: }
6416:
6417: inline void pcbios_int_10h_07h()
6418: {
1.1.1.14 root 6419: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6420: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6421: return;
6422: }
6423: vram_flush();
6424:
1.1.1.23 root 6425: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6426: SMALL_RECT rect;
1.1.1.14 root 6427: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6428: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6429:
6430: int right = min(REG8(DL), scr_width - 1);
6431: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6432:
6433: if(REG8(AL) == 0) {
1.1.1.14 root 6434: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6435: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6436: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6437: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6438: }
6439: }
6440: } else {
1.1.1.14 root 6441: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 6442: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6443: if(y2 >= REG8(CH)) {
6444: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6445: } else {
1.1.1.14 root 6446: SCR_BUF(y,x).Char.AsciiChar = ' ';
6447: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6448: }
1.1.1.14 root 6449: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6450: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6451: }
6452: }
6453: }
1.1.1.14 root 6454: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6455: }
6456:
6457: inline void pcbios_int_10h_08h()
6458: {
6459: COORD co;
6460: DWORD num;
6461:
1.1.1.14 root 6462: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6463: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6464:
6465: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6466: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6467: co.Y += scr_top;
6468: vram_flush();
1.1 root 6469: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
6470: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
6471: REG8(AL) = scr_char[0];
6472: REG8(AH) = scr_attr[0];
6473: } else {
1.1.1.16 root 6474: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 6475: }
6476: }
6477:
6478: inline void pcbios_int_10h_09h()
6479: {
6480: COORD co;
6481:
1.1.1.14 root 6482: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6483: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6484:
1.1.1.16 root 6485: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6486: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6487:
6488: if(mem[0x462] == REG8(BH)) {
1.1.1.35! root 6489: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6490: EnterCriticalSection(&vram_crit_sect);
1.1.1.35! root 6491: #endif
1.1.1.16 root 6492: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6493: while(dest < end) {
6494: write_text_vram_char(dest - vram, REG8(AL));
6495: mem[dest++] = REG8(AL);
6496: write_text_vram_attr(dest - vram, REG8(BL));
6497: mem[dest++] = REG8(BL);
1.1 root 6498: }
1.1.1.35! root 6499: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6500: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35! root 6501: #endif
1.1 root 6502: } else {
1.1.1.14 root 6503: while(dest < end) {
1.1 root 6504: mem[dest++] = REG8(AL);
6505: mem[dest++] = REG8(BL);
6506: }
6507: }
6508: }
6509:
6510: inline void pcbios_int_10h_0ah()
6511: {
6512: COORD co;
6513:
1.1.1.14 root 6514: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6515: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6516:
1.1.1.16 root 6517: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6518: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6519:
6520: if(mem[0x462] == REG8(BH)) {
1.1.1.35! root 6521: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6522: EnterCriticalSection(&vram_crit_sect);
1.1.1.35! root 6523: #endif
1.1.1.16 root 6524: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6525: while(dest < end) {
6526: write_text_vram_char(dest - vram, REG8(AL));
6527: mem[dest++] = REG8(AL);
6528: dest++;
1.1 root 6529: }
1.1.1.35! root 6530: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6531: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35! root 6532: #endif
1.1 root 6533: } else {
1.1.1.14 root 6534: while(dest < end) {
1.1 root 6535: mem[dest++] = REG8(AL);
6536: dest++;
6537: }
6538: }
6539: }
6540:
6541: inline void pcbios_int_10h_0eh()
6542: {
1.1.1.14 root 6543: DWORD num;
6544: COORD co;
6545:
6546: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6547: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6548:
6549: if(REG8(AL) == 7) {
6550: //MessageBeep(-1);
6551: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
6552: if(REG8(AL) == 10) {
6553: vram_flush();
6554: }
1.1.1.23 root 6555: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 6556: cursor_moved = true;
6557: } else {
1.1.1.16 root 6558: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 6559: if(mem[0x462] == REG8(BH)) {
1.1.1.35! root 6560: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6561: EnterCriticalSection(&vram_crit_sect);
1.1.1.35! root 6562: #endif
1.1.1.16 root 6563: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6564: write_text_vram_char(dest - vram, REG8(AL));
1.1.1.35! root 6565: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6566: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35! root 6567: #endif
1.1.1.14 root 6568:
1.1.1.23 root 6569: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6570: if(++co.X == scr_width) {
6571: co.X = 0;
6572: if(++co.Y == scr_height) {
6573: vram_flush();
6574: WriteConsole(hStdout, "\n", 1, &num, NULL);
6575: cursor_moved = true;
6576: }
6577: }
6578: if(!cursor_moved) {
6579: co.Y += scr_top;
6580: SetConsoleCursorPosition(hStdout, co);
6581: cursor_moved = true;
6582: }
6583: }
6584: mem[dest] = REG8(AL);
6585: }
1.1 root 6586: }
6587:
6588: inline void pcbios_int_10h_0fh()
6589: {
6590: REG8(AL) = mem[0x449];
6591: REG8(AH) = mem[0x44a];
6592: REG8(BH) = mem[0x462];
6593: }
6594:
1.1.1.14 root 6595: inline void pcbios_int_10h_11h()
6596: {
6597: switch(REG8(AL)) {
1.1.1.16 root 6598: case 0x01:
1.1.1.14 root 6599: case 0x11:
1.1.1.16 root 6600: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 6601: break;
1.1.1.16 root 6602: case 0x02:
1.1.1.14 root 6603: case 0x12:
1.1.1.16 root 6604: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6605: break;
1.1.1.16 root 6606: case 0x04:
1.1.1.14 root 6607: case 0x14:
1.1.1.16 root 6608: pcbios_set_console_size(80, 25, true);
6609: break;
6610: case 0x18:
6611: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6612: break;
6613: case 0x30:
6614: SREG(ES) = 0;
6615: i386_load_segment_descriptor(ES);
6616: REG16(BP) = 0;
6617: REG16(CX) = mem[0x485];
6618: REG8(DL) = mem[0x484];
6619: break;
6620: }
6621: }
6622:
6623: inline void pcbios_int_10h_12h()
6624: {
1.1.1.16 root 6625: switch(REG8(BL)) {
6626: case 0x10:
1.1.1.14 root 6627: REG16(BX) = 0x0003;
6628: REG16(CX) = 0x0009;
1.1.1.16 root 6629: break;
1.1.1.14 root 6630: }
6631: }
6632:
1.1 root 6633: inline void pcbios_int_10h_13h()
6634: {
1.1.1.3 root 6635: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 6636: COORD co;
6637: DWORD num;
6638:
6639: co.X = REG8(DL);
1.1.1.14 root 6640: co.Y = REG8(DH) + scr_top;
6641:
6642: vram_flush();
1.1 root 6643:
6644: switch(REG8(AL)) {
6645: case 0x00:
6646: case 0x01:
6647: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6648: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6649: CONSOLE_SCREEN_BUFFER_INFO csbi;
6650: GetConsoleScreenBufferInfo(hStdout, &csbi);
6651: SetConsoleCursorPosition(hStdout, co);
6652:
6653: if(csbi.wAttributes != REG8(BL)) {
6654: SetConsoleTextAttribute(hStdout, REG8(BL));
6655: }
1.1.1.14 root 6656: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
6657:
1.1 root 6658: if(csbi.wAttributes != REG8(BL)) {
6659: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
6660: }
6661: if(REG8(AL) == 0x00) {
1.1.1.15 root 6662: if(!restore_console_on_exit) {
6663: GetConsoleScreenBufferInfo(hStdout, &csbi);
6664: scr_top = csbi.srWindow.Top;
6665: }
1.1.1.14 root 6666: co.X = mem[0x450 + REG8(BH) * 2];
6667: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 6668: SetConsoleCursorPosition(hStdout, co);
6669: } else {
6670: cursor_moved = true;
6671: }
6672: } else {
1.1.1.3 root 6673: m_CF = 1;
1.1 root 6674: }
6675: break;
6676: case 0x02:
6677: case 0x03:
6678: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6679: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6680: CONSOLE_SCREEN_BUFFER_INFO csbi;
6681: GetConsoleScreenBufferInfo(hStdout, &csbi);
6682: SetConsoleCursorPosition(hStdout, co);
6683:
6684: WORD wAttributes = csbi.wAttributes;
6685: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
6686: if(wAttributes != mem[ofs + 1]) {
6687: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
6688: wAttributes = mem[ofs + 1];
6689: }
1.1.1.14 root 6690: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 6691: }
6692: if(csbi.wAttributes != wAttributes) {
6693: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
6694: }
6695: if(REG8(AL) == 0x02) {
1.1.1.14 root 6696: co.X = mem[0x450 + REG8(BH) * 2];
6697: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 6698: SetConsoleCursorPosition(hStdout, co);
6699: } else {
6700: cursor_moved = true;
6701: }
6702: } else {
1.1.1.3 root 6703: m_CF = 1;
1.1 root 6704: }
6705: break;
6706: case 0x10:
6707: case 0x11:
6708: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6709: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6710: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
6711: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
6712: for(int i = 0; i < num; i++) {
6713: mem[ofs++] = scr_char[i];
6714: mem[ofs++] = scr_attr[i];
6715: if(REG8(AL) == 0x11) {
6716: mem[ofs++] = 0;
6717: mem[ofs++] = 0;
6718: }
6719: }
6720: } else {
1.1.1.16 root 6721: 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 6722: mem[ofs++] = mem[src++];
6723: mem[ofs++] = mem[src++];
6724: if(REG8(AL) == 0x11) {
6725: mem[ofs++] = 0;
6726: mem[ofs++] = 0;
6727: }
1.1.1.14 root 6728: if(++co.X == scr_width) {
6729: if(++co.Y == scr_height) {
1.1 root 6730: break;
6731: }
6732: co.X = 0;
6733: }
6734: }
6735: }
6736: break;
6737: case 0x20:
6738: case 0x21:
6739: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6740: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6741: int len = min(REG16(CX), scr_width * scr_height);
6742: for(int i = 0; i < len; i++) {
1.1 root 6743: scr_char[i] = mem[ofs++];
6744: scr_attr[i] = mem[ofs++];
6745: if(REG8(AL) == 0x21) {
6746: ofs += 2;
6747: }
6748: }
1.1.1.14 root 6749: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
6750: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 6751: } else {
1.1.1.16 root 6752: 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 6753: mem[dest++] = mem[ofs++];
6754: mem[dest++] = mem[ofs++];
6755: if(REG8(AL) == 0x21) {
6756: ofs += 2;
6757: }
1.1.1.14 root 6758: if(++co.X == scr_width) {
6759: if(++co.Y == scr_height) {
1.1 root 6760: break;
6761: }
6762: co.X = 0;
6763: }
6764: }
6765: }
6766: break;
6767: default:
1.1.1.22 root 6768: 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 6769: m_CF = 1;
1.1 root 6770: break;
6771: }
6772: }
6773:
1.1.1.30 root 6774: inline void pcbios_int_10h_18h()
6775: {
6776: switch(REG8(AL)) {
6777: case 0x00:
6778: case 0x01:
6779: // REG8(AL) = 0x86;
6780: REG8(AL) = 0x00;
6781: break;
6782: default:
6783: 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));
6784: m_CF = 1;
6785: break;
6786: }
6787: }
6788:
1.1.1.14 root 6789: inline void pcbios_int_10h_1ah()
6790: {
6791: switch(REG8(AL)) {
6792: case 0x00:
6793: REG8(AL) = 0x1a;
6794: REG8(BL) = 0x08;
6795: REG8(BH) = 0x00;
6796: break;
6797: default:
1.1.1.22 root 6798: 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 6799: m_CF = 1;
6800: break;
6801: }
6802: }
6803:
1.1 root 6804: inline void pcbios_int_10h_1dh()
6805: {
6806: switch(REG8(AL)) {
6807: case 0x01:
6808: break;
6809: case 0x02:
6810: REG16(BX) = 0;
6811: break;
6812: default:
1.1.1.22 root 6813: 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));
6814: m_CF = 1;
6815: break;
6816: }
6817: }
6818:
6819: inline void pcbios_int_10h_4fh()
6820: {
6821: switch(REG8(AL)) {
6822: case 0x00:
6823: REG8(AH) = 0x02; // not supported
6824: break;
6825: case 0x01:
6826: case 0x02:
6827: case 0x03:
6828: case 0x04:
6829: case 0x05:
6830: case 0x06:
6831: case 0x07:
6832: case 0x08:
6833: case 0x09:
6834: case 0x0a:
6835: case 0x0b:
6836: case 0x0c:
6837: REG8(AH) = 0x01; // failed
6838: break;
6839: default:
6840: 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 6841: m_CF = 1;
1.1 root 6842: break;
6843: }
6844: }
6845:
6846: inline void pcbios_int_10h_82h()
6847: {
6848: static UINT8 mode = 0;
6849:
6850: switch(REG8(AL)) {
1.1.1.22 root 6851: case 0x00:
1.1 root 6852: if(REG8(BL) != 0xff) {
6853: mode = REG8(BL);
6854: }
6855: REG8(AL) = mode;
6856: break;
6857: default:
1.1.1.22 root 6858: 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 6859: m_CF = 1;
1.1 root 6860: break;
6861: }
6862: }
6863:
1.1.1.22 root 6864: inline void pcbios_int_10h_83h()
6865: {
6866: static UINT8 mode = 0;
6867:
6868: switch(REG8(AL)) {
6869: case 0x00:
6870: REG16(AX) = 0; // offset???
6871: SREG(ES) = (SHADOW_BUF_TOP >> 4);
6872: i386_load_segment_descriptor(ES);
6873: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
6874: break;
6875: default:
6876: 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));
6877: m_CF = 1;
6878: break;
6879: }
6880: }
6881:
6882: inline void pcbios_int_10h_90h()
6883: {
6884: REG8(AL) = mem[0x449];
6885: }
6886:
6887: inline void pcbios_int_10h_91h()
6888: {
6889: REG8(AL) = 0x04; // VGA
6890: }
6891:
6892: inline void pcbios_int_10h_efh()
6893: {
6894: REG16(DX) = 0xffff;
6895: }
6896:
1.1 root 6897: inline void pcbios_int_10h_feh()
6898: {
6899: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6900: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 6901: i386_load_segment_descriptor(ES);
1.1.1.8 root 6902: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 6903: }
6904: int_10h_feh_called = true;
6905: }
6906:
6907: inline void pcbios_int_10h_ffh()
6908: {
6909: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 6910: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6911: COORD co;
6912: DWORD num;
6913:
1.1.1.14 root 6914: vram_flush();
6915:
6916: co.X = (REG16(DI) >> 1) % scr_width;
6917: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 6918: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
6919: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 6920: int len;
6921: for(len = 0; ofs < end; len++) {
6922: scr_char[len] = mem[ofs++];
6923: scr_attr[len] = mem[ofs++];
6924: }
6925: co.Y += scr_top;
6926: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
6927: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 6928: }
6929: int_10h_ffh_called = true;
6930: }
6931:
1.1.1.25 root 6932: inline void pcbios_int_14h_00h()
6933: {
1.1.1.29 root 6934: if(REG16(DX) < 4) {
1.1.1.25 root 6935: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
6936: UINT8 selector = sio_read(REG16(DX), 3);
6937: selector &= ~0x3f;
6938: selector |= REG8(AL) & 0x1f;
6939: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
6940: sio_write(REG16(DX), 3, selector | 0x80);
6941: sio_write(REG16(DX), 0, divisor & 0xff);
6942: sio_write(REG16(DX), 1, divisor >> 8);
6943: sio_write(REG16(DX), 3, selector);
6944: REG8(AH) = sio_read(REG16(DX), 5);
6945: REG8(AL) = sio_read(REG16(DX), 6);
6946: } else {
6947: REG8(AH) = 0x80;
6948: }
6949: }
6950:
6951: inline void pcbios_int_14h_01h()
6952: {
1.1.1.29 root 6953: if(REG16(DX) < 4) {
1.1.1.25 root 6954: UINT8 selector = sio_read(REG16(DX), 3);
6955: sio_write(REG16(DX), 3, selector & ~0x80);
6956: sio_write(REG16(DX), 0, REG8(AL));
6957: sio_write(REG16(DX), 3, selector);
6958: REG8(AH) = sio_read(REG16(DX), 5);
6959: } else {
6960: REG8(AH) = 0x80;
6961: }
6962: }
6963:
6964: inline void pcbios_int_14h_02h()
6965: {
1.1.1.29 root 6966: if(REG16(DX) < 4) {
1.1.1.25 root 6967: UINT8 selector = sio_read(REG16(DX), 3);
6968: sio_write(REG16(DX), 3, selector & ~0x80);
6969: REG8(AL) = sio_read(REG16(DX), 0);
6970: sio_write(REG16(DX), 3, selector);
6971: REG8(AH) = sio_read(REG16(DX), 5);
6972: } else {
6973: REG8(AH) = 0x80;
6974: }
6975: }
6976:
6977: inline void pcbios_int_14h_03h()
6978: {
1.1.1.29 root 6979: if(REG16(DX) < 4) {
1.1.1.25 root 6980: REG8(AH) = sio_read(REG16(DX), 5);
6981: REG8(AL) = sio_read(REG16(DX), 6);
6982: } else {
6983: REG8(AH) = 0x80;
6984: }
6985: }
6986:
6987: inline void pcbios_int_14h_04h()
6988: {
1.1.1.29 root 6989: if(REG16(DX) < 4) {
1.1.1.25 root 6990: UINT8 selector = sio_read(REG16(DX), 3);
6991: if(REG8(CH) <= 0x03) {
6992: selector = (selector & ~0x03) | REG8(CH);
6993: }
6994: if(REG8(BL) == 0x00) {
6995: selector &= ~0x04;
6996: } else if(REG8(BL) == 0x01) {
6997: selector |= 0x04;
6998: }
6999: if(REG8(BH) == 0x00) {
7000: selector = (selector & ~0x38) | 0x00;
7001: } else if(REG8(BH) == 0x01) {
7002: selector = (selector & ~0x38) | 0x08;
7003: } else if(REG8(BH) == 0x02) {
7004: selector = (selector & ~0x38) | 0x18;
7005: } else if(REG8(BH) == 0x03) {
7006: selector = (selector & ~0x38) | 0x28;
7007: } else if(REG8(BH) == 0x04) {
7008: selector = (selector & ~0x38) | 0x38;
7009: }
7010: if(REG8(AL) == 0x00) {
7011: selector |= 0x40;
7012: } else if(REG8(AL) == 0x01) {
7013: selector &= ~0x40;
7014: }
7015: if(REG8(CL) <= 0x0b) {
7016: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
7017: UINT16 divisor = 115200 / rate[REG8(CL)];
7018: sio_write(REG16(DX), 3, selector | 0x80);
7019: sio_write(REG16(DX), 0, divisor & 0xff);
7020: sio_write(REG16(DX), 1, divisor >> 8);
7021: }
7022: sio_write(REG16(DX), 3, selector);
7023: REG8(AH) = sio_read(REG16(DX), 5);
7024: REG8(AL) = sio_read(REG16(DX), 6);
7025: } else {
7026: REG8(AH) = 0x80;
7027: }
7028: }
7029:
7030: inline void pcbios_int_14h_05h()
7031: {
1.1.1.29 root 7032: if(REG16(DX) < 4) {
1.1.1.25 root 7033: if(REG8(AL) == 0x00) {
7034: REG8(BL) = sio_read(REG16(DX), 4);
7035: REG8(AH) = sio_read(REG16(DX), 5);
7036: REG8(AL) = sio_read(REG16(DX), 6);
7037: } else if(REG8(AL) == 0x01) {
7038: sio_write(REG16(DX), 4, REG8(BL));
7039: REG8(AH) = sio_read(REG16(DX), 5);
7040: REG8(AL) = sio_read(REG16(DX), 6);
7041: } else {
7042: 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));
7043: }
7044: } else {
7045: REG8(AH) = 0x80;
7046: }
7047: }
7048:
1.1.1.14 root 7049: inline void pcbios_int_15h_10h()
7050: {
1.1.1.22 root 7051: switch(REG8(AL)) {
7052: case 0x00:
1.1.1.14 root 7053: Sleep(10);
1.1.1.35! root 7054: REQUEST_HARDWRE_UPDATE();
1.1.1.22 root 7055: break;
7056: default:
7057: 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 7058: REG8(AH) = 0x86;
7059: m_CF = 1;
7060: }
7061: }
7062:
1.1 root 7063: inline void pcbios_int_15h_23h()
7064: {
7065: switch(REG8(AL)) {
1.1.1.22 root 7066: case 0x00:
1.1.1.8 root 7067: REG8(CL) = cmos_read(0x2d);
7068: REG8(CH) = cmos_read(0x2e);
1.1 root 7069: break;
1.1.1.22 root 7070: case 0x01:
1.1.1.8 root 7071: cmos_write(0x2d, REG8(CL));
7072: cmos_write(0x2e, REG8(CH));
1.1 root 7073: break;
7074: default:
1.1.1.22 root 7075: 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 7076: REG8(AH) = 0x86;
1.1.1.3 root 7077: m_CF = 1;
1.1 root 7078: break;
7079: }
7080: }
7081:
7082: inline void pcbios_int_15h_24h()
7083: {
7084: switch(REG8(AL)) {
1.1.1.22 root 7085: case 0x00:
1.1.1.3 root 7086: i386_set_a20_line(0);
1.1 root 7087: REG8(AH) = 0;
7088: break;
1.1.1.22 root 7089: case 0x01:
1.1.1.3 root 7090: i386_set_a20_line(1);
1.1 root 7091: REG8(AH) = 0;
7092: break;
1.1.1.22 root 7093: case 0x02:
1.1 root 7094: REG8(AH) = 0;
1.1.1.3 root 7095: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 7096: REG16(CX) = 0;
7097: break;
1.1.1.22 root 7098: case 0x03:
1.1 root 7099: REG16(AX) = 0;
7100: REG16(BX) = 0;
7101: break;
1.1.1.22 root 7102: default:
7103: 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));
7104: REG8(AH) = 0x86;
7105: m_CF = 1;
7106: break;
1.1 root 7107: }
7108: }
7109:
7110: inline void pcbios_int_15h_49h()
7111: {
1.1.1.27 root 7112: REG8(AH) = 0x00;
7113: REG8(BL) = 0x00; // DOS/V
1.1 root 7114: }
7115:
1.1.1.22 root 7116: inline void pcbios_int_15h_50h()
7117: {
7118: switch(REG8(AL)) {
7119: case 0x00:
7120: case 0x01:
7121: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
7122: REG8(AH) = 0x01; // invalid font type in bh
7123: m_CF = 1;
1.1.1.27 root 7124: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 7125: REG8(AH) = 0x02; // bl not zero
7126: m_CF = 1;
7127: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
7128: REG8(AH) = 0x04; // invalid code page
7129: m_CF = 1;
1.1.1.27 root 7130: } else if(REG8(AL) == 0x01) {
7131: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 7132: m_CF = 1;
1.1.1.27 root 7133: } else {
7134: // dummy font read routine is at fffd:000d
7135: SREG(ES) = 0xfffd;
7136: i386_load_segment_descriptor(ES);
1.1.1.32 root 7137: REG16(BX) = 0x000d;
1.1.1.27 root 7138: REG8(AH) = 0x00; // success
1.1.1.22 root 7139: }
7140: break;
7141: default:
7142: 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));
7143: REG8(AH) = 0x86;
7144: m_CF = 1;
7145: break;
7146: }
7147: }
7148:
1.1.1.30 root 7149: inline void pcbios_int_15h_53h()
7150: {
7151: switch(REG8(AL)) {
7152: case 0x00:
7153: // APM is not installed
7154: REG8(AH) = 0x86;
7155: m_CF = 1;
7156: break;
7157: default:
7158: 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));
7159: REG8(AH) = 0x86;
7160: m_CF = 1;
7161: break;
7162: }
7163: }
7164:
1.1.1.35! root 7165:
! 7166: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID)
1.1 root 7167: {
7168: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 7169: UINT32 msec = usec / 1000;
7170:
1.1.1.35! root 7171: while(msec && !m_halted) {
1.1.1.14 root 7172: UINT32 tmp = min(msec, 100);
7173: if(msec - tmp < 10) {
7174: tmp = msec;
7175: }
7176: Sleep(tmp);
7177: msec -= tmp;
7178: }
1.1.1.35! root 7179:
! 7180: #ifdef USE_SERVICE_THREAD
! 7181: service_exit = true;
! 7182: #endif
! 7183: return(0);
! 7184: }
! 7185:
! 7186: inline void pcbios_int_15h_86h()
! 7187: {
! 7188: if(!(REG16(CX) == 0 && REG16(DX) == 0)) {
! 7189: #ifdef USE_SERVICE_THREAD
! 7190: start_service_loop(pcbios_int_15h_86h_thread);
! 7191: #else
! 7192: pcbios_int_15h_86h_thread(NULL);
! 7193: REQUEST_HARDWRE_UPDATE();
! 7194: #endif
! 7195: }
1.1 root 7196: }
7197:
7198: inline void pcbios_int_15h_87h()
7199: {
7200: // copy extended memory (from DOSBox)
7201: int len = REG16(CX) * 2;
1.1.1.3 root 7202: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 7203: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
7204: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
7205: memcpy(mem + dst, mem + src, len);
7206: REG16(AX) = 0x00;
7207: }
7208:
7209: inline void pcbios_int_15h_88h()
7210: {
1.1.1.17 root 7211: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 7212: }
7213:
7214: inline void pcbios_int_15h_89h()
7215: {
1.1.1.21 root 7216: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 7217: // switch to protected mode (from DOSBox)
7218: write_io_byte(0x20, 0x10);
7219: write_io_byte(0x21, REG8(BH));
7220: write_io_byte(0x21, 0x00);
7221: write_io_byte(0xa0, 0x10);
7222: write_io_byte(0xa1, REG8(BL));
7223: write_io_byte(0xa1, 0x00);
1.1.1.3 root 7224: i386_set_a20_line(1);
7225: int ofs = SREG_BASE(ES) + REG16(SI);
7226: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
7227: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
7228: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
7229: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
7230: #if defined(HAS_I386)
7231: m_cr[0] |= 1;
7232: #else
7233: m_msw |= 1;
7234: #endif
7235: SREG(DS) = 0x18;
7236: SREG(ES) = 0x20;
7237: SREG(SS) = 0x28;
7238: i386_load_segment_descriptor(DS);
7239: i386_load_segment_descriptor(ES);
7240: i386_load_segment_descriptor(SS);
1.1.1.21 root 7241: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 7242: REG16(SP) += 6;
1.1.1.3 root 7243: #if defined(HAS_I386)
1.1.1.21 root 7244: UINT32 flags = get_flags();
7245: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7246: set_flags(flags);
1.1.1.3 root 7247: #else
1.1.1.21 root 7248: UINT32 flags = CompressFlags();
7249: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7250: ExpandFlags(flags);
1.1.1.3 root 7251: #endif
1.1 root 7252: REG16(AX) = 0x00;
1.1.1.21 root 7253: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 7254: #else
1.1.1.21 root 7255: // i86/i186/v30: protected mode is not supported
1.1 root 7256: REG8(AH) = 0x86;
1.1.1.3 root 7257: m_CF = 1;
1.1 root 7258: #endif
7259: }
7260:
1.1.1.21 root 7261: inline void pcbios_int_15h_8ah()
7262: {
7263: UINT32 size = MAX_MEM - 0x100000;
7264: REG16(AX) = size & 0xffff;
7265: REG16(DX) = size >> 16;
7266: }
7267:
1.1.1.3 root 7268: #if defined(HAS_I386)
1.1 root 7269: inline void pcbios_int_15h_c9h()
7270: {
7271: REG8(AH) = 0x00;
7272: REG8(CH) = cpu_type;
7273: REG8(CL) = cpu_step;
7274: }
1.1.1.3 root 7275: #endif
1.1 root 7276:
7277: inline void pcbios_int_15h_cah()
7278: {
7279: switch(REG8(AL)) {
1.1.1.22 root 7280: case 0x00:
1.1 root 7281: if(REG8(BL) > 0x3f) {
7282: REG8(AH) = 0x03;
1.1.1.3 root 7283: m_CF = 1;
1.1 root 7284: } else if(REG8(BL) < 0x0e) {
7285: REG8(AH) = 0x04;
1.1.1.3 root 7286: m_CF = 1;
1.1 root 7287: } else {
1.1.1.8 root 7288: REG8(CL) = cmos_read(REG8(BL));
1.1 root 7289: }
7290: break;
1.1.1.22 root 7291: case 0x01:
1.1 root 7292: if(REG8(BL) > 0x3f) {
7293: REG8(AH) = 0x03;
1.1.1.3 root 7294: m_CF = 1;
1.1 root 7295: } else if(REG8(BL) < 0x0e) {
7296: REG8(AH) = 0x04;
1.1.1.3 root 7297: m_CF = 1;
1.1 root 7298: } else {
1.1.1.8 root 7299: cmos_write(REG8(BL), REG8(CL));
1.1 root 7300: }
7301: break;
7302: default:
1.1.1.22 root 7303: 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 7304: REG8(AH) = 0x86;
1.1.1.3 root 7305: m_CF = 1;
1.1 root 7306: break;
7307: }
7308: }
7309:
1.1.1.22 root 7310: inline void pcbios_int_15h_e8h()
1.1.1.17 root 7311: {
1.1.1.22 root 7312: switch(REG8(AL)) {
7313: #if defined(HAS_I386)
7314: case 0x01:
7315: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
7316: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
7317: break;
1.1.1.17 root 7318: #endif
1.1.1.22 root 7319: default:
7320: 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));
7321: REG8(AH) = 0x86;
7322: m_CF = 1;
7323: break;
7324: }
7325: }
1.1.1.17 root 7326:
1.1.1.33 root 7327: void pcbios_update_key_code(bool wait)
1.1 root 7328: {
1.1.1.32 root 7329: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 7330: #ifdef USE_SERVICE_THREAD
! 7331: EnterCriticalSection(&key_buf_crit_sect);
! 7332: #endif
! 7333: bool empty = key_buf_char->empty();
! 7334: #ifdef USE_SERVICE_THREAD
! 7335: LeaveCriticalSection(&key_buf_crit_sect);
! 7336: #endif
! 7337: if(empty) {
1.1.1.32 root 7338: if(!update_key_buffer()) {
1.1.1.33 root 7339: if(wait) {
1.1.1.32 root 7340: Sleep(10);
7341: } else {
7342: maybe_idle();
7343: }
1.1.1.14 root 7344: }
7345: }
1.1.1.34 root 7346: }
7347: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 7348: #ifdef USE_SERVICE_THREAD
! 7349: EnterCriticalSection(&key_buf_crit_sect);
! 7350: #endif
1.1.1.32 root 7351: if(key_buf_char->count() != 0) {
1.1.1.35! root 7352: key_code = key_buf_char->read() << 0;
! 7353: key_code |= key_buf_scan->read() << 8;
! 7354: key_recv = 0x0000ffff;
1.1.1.32 root 7355: }
7356: if(key_buf_char->count() != 0) {
1.1.1.35! root 7357: key_code |= key_buf_char->read() << 16;
! 7358: key_code |= key_buf_scan->read() << 24;
1.1.1.33 root 7359: key_recv |= 0xffff0000;
1.1.1.32 root 7360: }
1.1.1.35! root 7361: #ifdef USE_SERVICE_THREAD
! 7362: LeaveCriticalSection(&key_buf_crit_sect);
! 7363: #endif
1.1 root 7364: }
7365: }
7366:
1.1.1.35! root 7367: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID)
1.1 root 7368: {
1.1.1.33 root 7369: while(key_recv == 0 && !m_halted) {
7370: pcbios_update_key_code(true);
1.1 root 7371: }
1.1.1.33 root 7372: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
7373: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
7374: if(REG8(AH) == 0x10) {
7375: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
7376: } else {
7377: key_code = ((key_code >> 16) & 0xff00);
7378: }
7379: key_recv >>= 16;
1.1 root 7380: }
7381: }
7382: REG16(AX) = key_code & 0xffff;
7383: key_code >>= 16;
1.1.1.33 root 7384: key_recv >>= 16;
1.1.1.35! root 7385:
! 7386: #ifdef USE_SERVICE_THREAD
! 7387: service_exit = true;
! 7388: #endif
! 7389: return(0);
! 7390: }
! 7391:
! 7392: inline void pcbios_int_16h_00h()
! 7393: {
! 7394: #ifdef USE_SERVICE_THREAD
! 7395: start_service_loop(pcbios_int_16h_00h_thread);
! 7396: #else
! 7397: pcbios_int_16h_00h_thread(NULL);
! 7398: REQUEST_HARDWRE_UPDATE();
! 7399: #endif
1.1 root 7400: }
7401:
7402: inline void pcbios_int_16h_01h()
7403: {
1.1.1.33 root 7404: if(key_recv == 0) {
7405: pcbios_update_key_code(false);
1.1.1.5 root 7406: }
1.1.1.33 root 7407: if(key_recv != 0) {
7408: UINT32 key_code_tmp = key_code;
7409: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
7410: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
7411: if(REG8(AH) == 0x11) {
7412: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
7413: } else {
7414: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
7415: }
7416: }
1.1 root 7417: }
1.1.1.5 root 7418: REG16(AX) = key_code_tmp & 0xffff;
1.1.1.3 root 7419: #if defined(HAS_I386)
1.1.1.33 root 7420: m_ZF = 0;
7421: #else
7422: m_ZeroVal = 1;
7423: #endif
7424: } else {
7425: #if defined(HAS_I386)
7426: m_ZF = 1;
1.1.1.3 root 7427: #else
1.1.1.33 root 7428: m_ZeroVal = 0;
1.1.1.3 root 7429: #endif
1.1.1.33 root 7430: }
1.1 root 7431: }
7432:
7433: inline void pcbios_int_16h_02h()
7434: {
7435: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
7436: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
7437: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
7438: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
7439: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
7440: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
7441: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
7442: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
7443: }
7444:
7445: inline void pcbios_int_16h_03h()
7446: {
7447: static UINT16 status = 0;
7448:
7449: switch(REG8(AL)) {
7450: case 0x05:
7451: status = REG16(BX);
7452: break;
7453: case 0x06:
7454: REG16(BX) = status;
7455: break;
7456: default:
1.1.1.3 root 7457: m_CF = 1;
1.1 root 7458: break;
7459: }
7460: }
7461:
7462: inline void pcbios_int_16h_05h()
7463: {
1.1.1.32 root 7464: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35! root 7465: #ifdef USE_SERVICE_THREAD
! 7466: EnterCriticalSection(&key_buf_crit_sect);
! 7467: #endif
1.1.1.32 root 7468: key_buf_char->write(REG8(CL));
7469: key_buf_scan->write(REG8(CH));
1.1.1.35! root 7470: #ifdef USE_SERVICE_THREAD
! 7471: LeaveCriticalSection(&key_buf_crit_sect);
! 7472: #endif
1.1.1.32 root 7473: }
1.1 root 7474: REG8(AL) = 0x00;
7475: }
7476:
7477: inline void pcbios_int_16h_12h()
7478: {
7479: pcbios_int_16h_02h();
7480:
7481: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
7482: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
7483: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
7484: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
7485: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
7486: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
7487: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
7488: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
7489: }
7490:
7491: inline void pcbios_int_16h_13h()
7492: {
7493: static UINT16 status = 0;
7494:
7495: switch(REG8(AL)) {
7496: case 0x00:
7497: status = REG16(DX);
7498: break;
7499: case 0x01:
7500: REG16(DX) = status;
7501: break;
7502: default:
1.1.1.22 root 7503: 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 7504: m_CF = 1;
1.1 root 7505: break;
7506: }
7507: }
7508:
7509: inline void pcbios_int_16h_14h()
7510: {
7511: static UINT8 status = 0;
7512:
7513: switch(REG8(AL)) {
7514: case 0x00:
7515: case 0x01:
7516: status = REG8(AL);
7517: break;
7518: case 0x02:
7519: REG8(AL) = status;
7520: break;
7521: default:
1.1.1.22 root 7522: 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 7523: m_CF = 1;
1.1 root 7524: break;
7525: }
7526: }
7527:
1.1.1.24 root 7528: inline void pcbios_int_16h_55h()
7529: {
7530: switch(REG8(AL)) {
7531: case 0x00:
7532: // keyboard tsr is not present
7533: break;
7534: case 0xfe:
7535: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
7536: break;
7537: case 0xff:
7538: break;
7539: default:
7540: 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));
7541: m_CF = 1;
7542: break;
7543: }
7544: }
7545:
1.1.1.30 root 7546: inline void pcbios_int_16h_6fh()
7547: {
7548: switch(REG8(AL)) {
7549: case 0x00:
7550: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
7551: break;
7552: default:
7553: 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));
7554: m_CF = 1;
7555: break;
7556: }
7557: }
7558:
1.1 root 7559: inline void pcbios_int_1ah_00h()
7560: {
1.1.1.19 root 7561: pcbios_update_daily_timer_counter(timeGetTime());
7562: REG16(CX) = *(UINT16 *)(mem + 0x46e);
7563: REG16(DX) = *(UINT16 *)(mem + 0x46c);
7564: REG8(AL) = mem[0x470];
7565: mem[0x470] = 0;
1.1 root 7566: }
7567:
7568: inline int to_bcd(int t)
7569: {
7570: int u = (t % 100) / 10;
7571: return (u << 4) | (t % 10);
7572: }
7573:
7574: inline void pcbios_int_1ah_02h()
7575: {
7576: SYSTEMTIME time;
7577:
7578: GetLocalTime(&time);
7579: REG8(CH) = to_bcd(time.wHour);
7580: REG8(CL) = to_bcd(time.wMinute);
7581: REG8(DH) = to_bcd(time.wSecond);
7582: REG8(DL) = 0x00;
7583: }
7584:
7585: inline void pcbios_int_1ah_04h()
7586: {
7587: SYSTEMTIME time;
7588:
7589: GetLocalTime(&time);
7590: REG8(CH) = to_bcd(time.wYear / 100);
7591: REG8(CL) = to_bcd(time.wYear);
7592: REG8(DH) = to_bcd(time.wMonth);
7593: REG8(DL) = to_bcd(time.wDay);
7594: }
7595:
7596: inline void pcbios_int_1ah_0ah()
7597: {
7598: SYSTEMTIME time;
7599: FILETIME file_time;
7600: WORD dos_date, dos_time;
7601:
7602: GetLocalTime(&time);
7603: SystemTimeToFileTime(&time, &file_time);
7604: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
7605: REG16(CX) = dos_date;
7606: }
7607:
7608: // msdos system call
7609:
7610: inline void msdos_int_21h_00h()
7611: {
1.1.1.3 root 7612: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 7613: }
7614:
1.1.1.35! root 7615: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID)
1.1 root 7616: {
7617: REG8(AL) = msdos_getche();
1.1.1.33 root 7618: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7619:
1.1.1.35! root 7620: #ifdef USE_SERVICE_THREAD
! 7621: service_exit = true;
! 7622: #endif
! 7623: return(0);
! 7624: }
! 7625:
! 7626: inline void msdos_int_21h_01h()
! 7627: {
! 7628: #ifdef USE_SERVICE_THREAD
! 7629: start_service_loop(msdos_int_21h_01h_thread);
! 7630: #else
! 7631: msdos_int_21h_01h_thread(NULL);
! 7632: REQUEST_HARDWRE_UPDATE();
! 7633: #endif
1.1 root 7634: }
7635:
7636: inline void msdos_int_21h_02h()
7637: {
1.1.1.33 root 7638: UINT8 data = REG8(DL);
7639: msdos_putch(data);
7640: REG8(AL) = data;
7641: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7642: }
7643:
7644: inline void msdos_int_21h_03h()
7645: {
7646: REG8(AL) = msdos_aux_in();
7647: }
7648:
7649: inline void msdos_int_21h_04h()
7650: {
7651: msdos_aux_out(REG8(DL));
7652: }
7653:
7654: inline void msdos_int_21h_05h()
7655: {
7656: msdos_prn_out(REG8(DL));
7657: }
7658:
7659: inline void msdos_int_21h_06h()
7660: {
7661: if(REG8(DL) == 0xff) {
7662: if(msdos_kbhit()) {
7663: REG8(AL) = msdos_getch();
1.1.1.3 root 7664: #if defined(HAS_I386)
7665: m_ZF = 0;
7666: #else
7667: m_ZeroVal = 1;
7668: #endif
1.1 root 7669: } else {
7670: REG8(AL) = 0;
1.1.1.3 root 7671: #if defined(HAS_I386)
7672: m_ZF = 1;
7673: #else
7674: m_ZeroVal = 0;
7675: #endif
1.1.1.14 root 7676: maybe_idle();
1.1 root 7677: }
7678: } else {
1.1.1.33 root 7679: UINT8 data = REG8(DL);
7680: msdos_putch(data);
7681: REG8(AL) = data;
1.1 root 7682: }
7683: }
7684:
1.1.1.35! root 7685: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID)
1.1 root 7686: {
7687: REG8(AL) = msdos_getch();
1.1.1.26 root 7688:
1.1.1.35! root 7689: #ifdef USE_SERVICE_THREAD
! 7690: service_exit = true;
! 7691: #endif
! 7692: return(0);
1.1 root 7693: }
7694:
1.1.1.35! root 7695: inline void msdos_int_21h_07h()
! 7696: {
! 7697: #ifdef USE_SERVICE_THREAD
! 7698: start_service_loop(msdos_int_21h_07h_thread);
! 7699: #else
! 7700: msdos_int_21h_07h_thread(NULL);
! 7701: REQUEST_HARDWRE_UPDATE();
! 7702: #endif
! 7703: }
! 7704:
! 7705: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID)
1.1 root 7706: {
7707: REG8(AL) = msdos_getch();
1.1.1.33 root 7708: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7709:
1.1.1.35! root 7710: #ifdef USE_SERVICE_THREAD
! 7711: service_exit = true;
! 7712: #endif
! 7713: return(0);
! 7714: }
! 7715:
! 7716: inline void msdos_int_21h_08h()
! 7717: {
! 7718: #ifdef USE_SERVICE_THREAD
! 7719: start_service_loop(msdos_int_21h_08h_thread);
! 7720: #else
! 7721: msdos_int_21h_08h_thread(NULL);
! 7722: REQUEST_HARDWRE_UPDATE();
! 7723: #endif
1.1 root 7724: }
7725:
7726: inline void msdos_int_21h_09h()
7727: {
1.1.1.21 root 7728: msdos_stdio_reopen();
7729:
1.1.1.20 root 7730: process_t *process = msdos_process_info_get(current_psp);
7731: int fd = msdos_psp_get_file_table(1, current_psp);
7732:
1.1.1.14 root 7733: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7734: int len = 0;
1.1 root 7735:
1.1.1.14 root 7736: while(str[len] != '$' && len < 0x10000) {
7737: len++;
7738: }
1.1.1.20 root 7739: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 7740: // stdout is redirected to file
1.1.1.20 root 7741: msdos_write(fd, str, len);
1.1 root 7742: } else {
7743: for(int i = 0; i < len; i++) {
1.1.1.14 root 7744: msdos_putch(str[i]);
1.1 root 7745: }
7746: }
1.1.1.33 root 7747: REG8(AL) = '$';
7748: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7749: }
7750:
1.1.1.35! root 7751: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID)
1.1 root 7752: {
1.1.1.3 root 7753: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 7754: int max = mem[ofs] - 1;
7755: UINT8 *buf = mem + ofs + 2;
7756: int chr, p = 0;
7757:
7758: while((chr = msdos_getch()) != 0x0d) {
1.1.1.33 root 7759: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 7760: p = 0;
1.1.1.33 root 7761: msdos_putch(0x03);
7762: msdos_putch(0x0d);
7763: msdos_putch(0x0a);
1.1.1.26 root 7764: break;
1.1.1.33 root 7765: } else if(ctrl_break_pressed) {
7766: // skip this byte
1.1.1.26 root 7767: } else if(chr == 0x00) {
1.1 root 7768: // skip 2nd byte
7769: msdos_getch();
7770: } else if(chr == 0x08) {
7771: // back space
7772: if(p > 0) {
7773: p--;
1.1.1.20 root 7774: if(msdos_ctrl_code_check(buf[p])) {
1.1.1.34 root 7775: msdos_putch(0x08);
7776: msdos_putch(0x08);
7777: msdos_putch(0x20);
7778: msdos_putch(0x20);
7779: msdos_putch(0x08);
7780: msdos_putch(0x08);
7781: } else {
7782: msdos_putch(0x08);
7783: msdos_putch(0x20);
7784: msdos_putch(0x08);
7785: }
7786: }
7787: } else if(chr == 0x1b) {
7788: // escape
7789: while(p > 0) {
7790: p--;
7791: if(msdos_ctrl_code_check(buf[p])) {
7792: msdos_putch(0x08);
7793: msdos_putch(0x08);
7794: msdos_putch(0x20);
7795: msdos_putch(0x20);
7796: msdos_putch(0x08);
7797: msdos_putch(0x08);
1.1.1.20 root 7798: } else {
1.1.1.34 root 7799: msdos_putch(0x08);
7800: msdos_putch(0x20);
7801: msdos_putch(0x08);
1.1.1.20 root 7802: }
1.1 root 7803: }
7804: } else if(p < max) {
7805: buf[p++] = chr;
7806: msdos_putch(chr);
7807: }
7808: }
7809: buf[p] = 0x0d;
7810: mem[ofs + 1] = p;
1.1.1.33 root 7811: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7812:
1.1.1.35! root 7813: #ifdef USE_SERVICE_THREAD
! 7814: service_exit = true;
! 7815: #endif
! 7816: return(0);
! 7817: }
! 7818:
! 7819: inline void msdos_int_21h_0ah()
! 7820: {
! 7821: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) {
! 7822: #ifdef USE_SERVICE_THREAD
! 7823: start_service_loop(msdos_int_21h_0ah_thread);
! 7824: #else
! 7825: msdos_int_21h_0ah_thread(NULL);
! 7826: REQUEST_HARDWRE_UPDATE();
! 7827: #endif
! 7828: }
1.1 root 7829: }
7830:
7831: inline void msdos_int_21h_0bh()
7832: {
7833: if(msdos_kbhit()) {
7834: REG8(AL) = 0xff;
7835: } else {
7836: REG8(AL) = 0x00;
1.1.1.14 root 7837: maybe_idle();
1.1 root 7838: }
1.1.1.33 root 7839: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7840: }
7841:
7842: inline void msdos_int_21h_0ch()
7843: {
7844: // clear key buffer
1.1.1.21 root 7845: msdos_stdio_reopen();
7846:
1.1.1.20 root 7847: process_t *process = msdos_process_info_get(current_psp);
7848: int fd = msdos_psp_get_file_table(0, current_psp);
7849:
7850: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 7851: // stdin is redirected to file
7852: } else {
7853: while(msdos_kbhit()) {
7854: msdos_getch();
7855: }
7856: }
7857:
7858: switch(REG8(AL)) {
7859: case 0x01:
7860: msdos_int_21h_01h();
7861: break;
7862: case 0x06:
7863: msdos_int_21h_06h();
7864: break;
7865: case 0x07:
7866: msdos_int_21h_07h();
7867: break;
7868: case 0x08:
7869: msdos_int_21h_08h();
7870: break;
7871: case 0x0a:
7872: msdos_int_21h_0ah();
7873: break;
7874: default:
1.1.1.22 root 7875: // 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));
7876: // REG16(AX) = 0x01;
7877: // m_CF = 1;
1.1 root 7878: break;
7879: }
7880: }
7881:
7882: inline void msdos_int_21h_0dh()
7883: {
7884: }
7885:
7886: inline void msdos_int_21h_0eh()
7887: {
7888: if(REG8(DL) < 26) {
7889: _chdrive(REG8(DL) + 1);
7890: msdos_cds_update(REG8(DL));
1.1.1.23 root 7891: msdos_sda_update(current_psp);
1.1 root 7892: }
7893: REG8(AL) = 26; // zdrive
7894: }
7895:
1.1.1.14 root 7896: inline void msdos_int_21h_0fh()
7897: {
7898: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7899: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7900: char *path = msdos_fcb_path(fcb);
7901: 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 7902:
1.1.1.14 root 7903: if(hFile == INVALID_HANDLE_VALUE) {
7904: REG8(AL) = 0xff;
7905: } else {
7906: REG8(AL) = 0;
7907: fcb->current_block = 0;
7908: fcb->record_size = 128;
7909: fcb->file_size = GetFileSize(hFile, NULL);
7910: fcb->handle = hFile;
7911: fcb->cur_record = 0;
7912: }
7913: }
7914:
7915: inline void msdos_int_21h_10h()
7916: {
7917: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7918: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7919:
7920: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
7921: }
7922:
1.1 root 7923: inline void msdos_int_21h_11h()
7924: {
1.1.1.3 root 7925: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7926: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7927:
7928: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7929: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7930: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
7931: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7932: char *path = msdos_fcb_path(fcb);
7933: WIN32_FIND_DATA fd;
7934:
1.1.1.13 root 7935: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
7936: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7937: FindClose(dtainfo->find_handle);
7938: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7939: }
7940: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7941: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
7942: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7943:
1.1.1.14 root 7944: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7945: dtainfo->allowable_mask &= ~8;
1.1 root 7946: }
1.1.1.14 root 7947: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7948: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7949: !msdos_find_file_has_8dot3name(&fd)) {
7950: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7951: FindClose(dtainfo->find_handle);
7952: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7953: break;
7954: }
7955: }
7956: }
1.1.1.13 root 7957: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7958: if(ext_fcb->flag == 0xff) {
7959: ext_find->flag = 0xff;
7960: memset(ext_find->reserved, 0, 5);
7961: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
7962: }
7963: find->drive = _getdrive();
1.1.1.13 root 7964: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 7965: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
7966: find->nt_res = 0;
7967: msdos_find_file_conv_local_time(&fd);
7968: find->create_time_ms = 0;
7969: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
7970: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
7971: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
7972: find->cluster_hi = find->cluster_lo = 0;
7973: find->file_size = fd.nFileSizeLow;
7974: REG8(AL) = 0x00;
1.1.1.14 root 7975: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7976: if(ext_fcb->flag == 0xff) {
7977: ext_find->flag = 0xff;
7978: memset(ext_find->reserved, 0, 5);
7979: ext_find->attribute = 8;
7980: }
7981: find->drive = _getdrive();
7982: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
7983: find->attribute = 8;
7984: find->nt_res = 0;
7985: msdos_find_file_conv_local_time(&fd);
7986: find->create_time_ms = 0;
7987: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
7988: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
7989: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
7990: find->cluster_hi = find->cluster_lo = 0;
7991: find->file_size = 0;
1.1.1.14 root 7992: dtainfo->allowable_mask &= ~8;
1.1 root 7993: REG8(AL) = 0x00;
7994: } else {
7995: REG8(AL) = 0xff;
7996: }
7997: }
7998:
7999: inline void msdos_int_21h_12h()
8000: {
1.1.1.3 root 8001: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 8002: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8003:
8004: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 8005: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8006: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
8007: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8008: WIN32_FIND_DATA fd;
8009:
1.1.1.13 root 8010: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
8011: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8012: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 8013: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 8014: !msdos_find_file_has_8dot3name(&fd)) {
8015: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8016: FindClose(dtainfo->find_handle);
8017: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8018: break;
8019: }
8020: }
8021: } else {
1.1.1.13 root 8022: FindClose(dtainfo->find_handle);
8023: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8024: }
8025: }
1.1.1.13 root 8026: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8027: if(ext_fcb->flag == 0xff) {
8028: ext_find->flag = 0xff;
8029: memset(ext_find->reserved, 0, 5);
8030: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8031: }
8032: find->drive = _getdrive();
1.1.1.13 root 8033: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 8034: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8035: find->nt_res = 0;
8036: msdos_find_file_conv_local_time(&fd);
8037: find->create_time_ms = 0;
8038: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8039: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8040: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8041: find->cluster_hi = find->cluster_lo = 0;
8042: find->file_size = fd.nFileSizeLow;
8043: REG8(AL) = 0x00;
1.1.1.14 root 8044: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8045: if(ext_fcb->flag == 0xff) {
8046: ext_find->flag = 0xff;
8047: memset(ext_find->reserved, 0, 5);
8048: ext_find->attribute = 8;
8049: }
8050: find->drive = _getdrive();
8051: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
8052: find->attribute = 8;
8053: find->nt_res = 0;
8054: msdos_find_file_conv_local_time(&fd);
8055: find->create_time_ms = 0;
8056: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8057: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8058: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8059: find->cluster_hi = find->cluster_lo = 0;
8060: find->file_size = 0;
1.1.1.14 root 8061: dtainfo->allowable_mask &= ~8;
1.1 root 8062: REG8(AL) = 0x00;
8063: } else {
8064: REG8(AL) = 0xff;
8065: }
8066: }
8067:
8068: inline void msdos_int_21h_13h()
8069: {
1.1.1.3 root 8070: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 8071: REG8(AL) = 0xff;
8072: } else {
8073: REG8(AL) = 0x00;
8074: }
8075: }
8076:
1.1.1.16 root 8077: inline void msdos_int_21h_14h()
8078: {
8079: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8080: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8081: process_t *process = msdos_process_info_get(current_psp);
8082: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8083: DWORD num = 0;
8084:
8085: memset(mem + dta_laddr, 0, fcb->record_size);
8086: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8087: REG8(AL) = 1;
8088: } else {
8089: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
8090: fcb->current_block = (position & 0xffffff) / fcb->record_size;
8091: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
8092: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
8093: }
8094: }
8095:
8096: inline void msdos_int_21h_15h()
1.1.1.14 root 8097: {
8098: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8099: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 8100: process_t *process = msdos_process_info_get(current_psp);
8101: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8102: DWORD num = 0;
1.1.1.14 root 8103:
1.1.1.16 root 8104: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8105: REG8(AL) = 1;
8106: } else {
8107: fcb->file_size = GetFileSize(fcb->handle, NULL);
8108: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
8109: fcb->current_block = (position & 0xffffff) / fcb->record_size;
8110: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
8111: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
8112: }
8113: }
8114:
8115: inline void msdos_int_21h_16h()
8116: {
8117: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8118: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 8119: char *path = msdos_fcb_path(fcb);
8120: 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 8121:
1.1.1.14 root 8122: if(hFile == INVALID_HANDLE_VALUE) {
8123: REG8(AL) = 0xff;
8124: } else {
8125: REG8(AL) = 0;
8126: fcb->current_block = 0;
8127: fcb->record_size = 128;
8128: fcb->file_size = 0;
8129: fcb->handle = hFile;
8130: fcb->cur_record = 0;
8131: }
8132: }
8133:
1.1.1.16 root 8134: inline void msdos_int_21h_17h()
8135: {
8136: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8137: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
8138: char *path_src = msdos_fcb_path(fcb_src);
8139: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
8140: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
8141: char *path_dst = msdos_fcb_path(fcb_dst);
8142:
8143: if(rename(path_src, path_dst)) {
8144: REG8(AL) = 0xff;
8145: } else {
8146: REG8(AL) = 0;
8147: }
8148: }
8149:
1.1 root 8150: inline void msdos_int_21h_18h()
8151: {
8152: REG8(AL) = 0x00;
8153: }
8154:
8155: inline void msdos_int_21h_19h()
8156: {
8157: REG8(AL) = _getdrive() - 1;
8158: }
8159:
8160: inline void msdos_int_21h_1ah()
8161: {
8162: process_t *process = msdos_process_info_get(current_psp);
8163:
8164: process->dta.w.l = REG16(DX);
1.1.1.3 root 8165: process->dta.w.h = SREG(DS);
1.1.1.23 root 8166: msdos_sda_update(current_psp);
1.1 root 8167: }
8168:
8169: inline void msdos_int_21h_1bh()
8170: {
8171: int drive_num = _getdrive() - 1;
8172: UINT16 seg, ofs;
8173:
8174: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8175: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8176: REG8(AL) = dpb->highest_sector_num + 1;
8177: REG16(CX) = dpb->bytes_per_sector;
8178: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 8179: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 8180: } else {
8181: REG8(AL) = 0xff;
1.1.1.3 root 8182: m_CF = 1;
1.1 root 8183: }
8184:
8185: }
8186:
8187: inline void msdos_int_21h_1ch()
8188: {
8189: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
8190: UINT16 seg, ofs;
8191:
8192: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8193: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8194: REG8(AL) = dpb->highest_sector_num + 1;
8195: REG16(CX) = dpb->bytes_per_sector;
8196: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 8197: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 8198: } else {
8199: REG8(AL) = 0xff;
1.1.1.3 root 8200: m_CF = 1;
1.1 root 8201: }
8202:
8203: }
8204:
8205: inline void msdos_int_21h_1dh()
8206: {
8207: REG8(AL) = 0;
8208: }
8209:
8210: inline void msdos_int_21h_1eh()
8211: {
8212: REG8(AL) = 0;
8213: }
8214:
8215: inline void msdos_int_21h_1fh()
8216: {
8217: int drive_num = _getdrive() - 1;
8218: UINT16 seg, ofs;
8219:
8220: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8221: REG8(AL) = 0;
1.1.1.3 root 8222: SREG(DS) = seg;
8223: i386_load_segment_descriptor(DS);
1.1 root 8224: REG16(BX) = ofs;
8225: } else {
8226: REG8(AL) = 0xff;
1.1.1.3 root 8227: m_CF = 1;
1.1 root 8228: }
8229: }
8230:
8231: inline void msdos_int_21h_20h()
8232: {
8233: REG8(AL) = 0;
8234: }
8235:
1.1.1.14 root 8236: inline void msdos_int_21h_21h()
8237: {
8238: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8239: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8240:
8241: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8242: REG8(AL) = 1;
8243: } else {
8244: process_t *process = msdos_process_info_get(current_psp);
8245: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8246: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 8247: DWORD num = 0;
1.1.1.14 root 8248: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8249: REG8(AL) = 1;
8250: } else {
8251: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8252: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 8253: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 8254: }
8255: }
8256: }
8257:
8258: inline void msdos_int_21h_22h()
8259: {
8260: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8261: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8262:
8263: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8264: REG8(AL) = 0xff;
8265: } else {
8266: process_t *process = msdos_process_info_get(current_psp);
8267: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 8268: DWORD num = 0;
1.1.1.14 root 8269: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
8270: fcb->file_size = GetFileSize(fcb->handle, NULL);
8271: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8272: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 8273: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 8274: }
8275: }
8276:
1.1.1.16 root 8277: inline void msdos_int_21h_23h()
8278: {
8279: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8280: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8281: char *path = msdos_fcb_path(fcb);
8282: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
8283:
8284: if(hFile == INVALID_HANDLE_VALUE) {
8285: REG8(AL) = 0xff;
8286: } else {
8287: UINT32 size = GetFileSize(hFile, NULL);
8288: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
8289: REG8(AL) = 0;
8290: }
8291: }
8292:
8293: inline void msdos_int_21h_24h()
8294: {
8295: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8296: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8297:
8298: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
8299: }
8300:
1.1 root 8301: inline void msdos_int_21h_25h()
8302: {
8303: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 8304: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 8305: }
8306:
8307: inline void msdos_int_21h_26h()
8308: {
8309: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
8310:
8311: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
8312: psp->first_mcb = REG16(DX) + 16;
8313: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
8314: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
8315: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
8316: psp->parent_psp = 0;
8317: }
8318:
1.1.1.16 root 8319: inline void msdos_int_21h_27h()
8320: {
8321: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8322: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8323:
8324: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8325: REG8(AL) = 1;
8326: } else {
8327: process_t *process = msdos_process_info_get(current_psp);
8328: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8329: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
8330: DWORD num = 0;
8331: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
8332: REG8(AL) = 1;
8333: } else {
8334: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8335: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
8336: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
8337: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
8338: }
8339: }
8340: }
8341:
8342: inline void msdos_int_21h_28h()
8343: {
8344: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8345: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8346:
8347: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8348: REG8(AL) = 0xff;
8349: } else {
8350: process_t *process = msdos_process_info_get(current_psp);
8351: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8352: DWORD num = 0;
8353: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
8354: fcb->file_size = GetFileSize(fcb->handle, NULL);
8355: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8356: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
8357: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
8358: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
8359: }
8360: }
8361:
1.1 root 8362: inline void msdos_int_21h_29h()
8363: {
1.1.1.20 root 8364: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
8365: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 8366: UINT8 drv = 0;
8367: char sep_chars[] = ":.;,=+";
8368: char end_chars[] = "\\<>|/\"[]";
8369: char spc_chars[] = " \t";
8370:
1.1.1.20 root 8371: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
8372: buffer[1023] = 0;
8373: memset(name, 0x20, sizeof(name));
8374: memset(ext, 0x20, sizeof(ext));
8375:
1.1 root 8376: if(REG8(AL) & 1) {
1.1.1.20 root 8377: ofs += strspn((char *)(buffer + ofs), spc_chars);
8378: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 8379: ofs++;
8380: }
8381: }
1.1.1.20 root 8382: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 8383:
1.1.1.24 root 8384: if(buffer[ofs + 1] == ':') {
8385: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
8386: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 8387: ofs += 2;
1.1.1.24 root 8388: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
8389: ofs++;
8390: }
8391: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
8392: drv = buffer[ofs] - 'A' + 1;
1.1 root 8393: ofs += 2;
1.1.1.24 root 8394: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
8395: ofs++;
8396: }
1.1 root 8397: }
8398: }
1.1.1.20 root 8399: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
8400: UINT8 c = buffer[ofs];
8401: if(is_kanji) {
8402: is_kanji = 0;
8403: } else if(msdos_lead_byte_check(c)) {
8404: is_kanji = 1;
8405: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 8406: break;
8407: } else if(c >= 'a' && c <= 'z') {
8408: c -= 0x20;
8409: }
8410: ofs++;
8411: name[i] = c;
8412: }
1.1.1.20 root 8413: if(buffer[ofs] == '.') {
1.1 root 8414: ofs++;
1.1.1.20 root 8415: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
8416: UINT8 c = buffer[ofs];
8417: if(is_kanji) {
8418: is_kanji = 0;
8419: } else if(msdos_lead_byte_check(c)) {
8420: is_kanji = 1;
8421: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 8422: break;
8423: } else if(c >= 'a' && c <= 'z') {
8424: c -= 0x20;
8425: }
8426: ofs++;
8427: ext[i] = c;
8428: }
8429: }
1.1.1.20 root 8430: int si = REG16(SI) + ofs;
1.1.1.3 root 8431: int ds = SREG(DS);
1.1 root 8432: while(si > 0xffff) {
8433: si -= 0x10;
8434: ds++;
8435: }
8436: REG16(SI) = si;
1.1.1.3 root 8437: SREG(DS) = ds;
8438: i386_load_segment_descriptor(DS);
1.1 root 8439:
1.1.1.3 root 8440: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 8441: if(!(REG8(AL) & 2) || drv != 0) {
8442: fcb[0] = drv;
8443: }
8444: if(!(REG8(AL) & 4) || name[0] != 0x20) {
8445: memcpy(fcb + 1, name, 8);
8446: }
8447: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
8448: memcpy(fcb + 9, ext, 3);
8449: }
8450: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 8451: if(fcb[i] == '*') {
8452: found_star = 1;
8453: }
8454: if(found_star) {
8455: fcb[i] = '?';
8456: }
8457: }
1.1.1.20 root 8458: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 8459: if(fcb[i] == '*') {
8460: found_star = 1;
8461: }
8462: if(found_star) {
8463: fcb[i] = '?';
8464: }
8465: }
8466:
8467: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
8468: if(memchr(fcb + 1, '?', 8 + 3)) {
8469: REG8(AL) = 0x01;
1.1.1.20 root 8470: } else {
8471: REG8(AL) = 0x00;
1.1 root 8472: }
8473: } else {
8474: REG8(AL) = 0xff;
8475: }
8476: }
8477:
8478: inline void msdos_int_21h_2ah()
8479: {
8480: SYSTEMTIME sTime;
8481:
8482: GetLocalTime(&sTime);
8483: REG16(CX) = sTime.wYear;
8484: REG8(DH) = (UINT8)sTime.wMonth;
8485: REG8(DL) = (UINT8)sTime.wDay;
8486: REG8(AL) = (UINT8)sTime.wDayOfWeek;
8487: }
8488:
8489: inline void msdos_int_21h_2bh()
8490: {
1.1.1.14 root 8491: REG8(AL) = 0xff;
1.1 root 8492: }
8493:
8494: inline void msdos_int_21h_2ch()
8495: {
8496: SYSTEMTIME sTime;
8497:
8498: GetLocalTime(&sTime);
8499: REG8(CH) = (UINT8)sTime.wHour;
8500: REG8(CL) = (UINT8)sTime.wMinute;
8501: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 8502: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 8503: }
8504:
8505: inline void msdos_int_21h_2dh()
8506: {
8507: REG8(AL) = 0x00;
8508: }
8509:
8510: inline void msdos_int_21h_2eh()
8511: {
8512: process_t *process = msdos_process_info_get(current_psp);
8513:
8514: process->verify = REG8(AL);
8515: }
8516:
8517: inline void msdos_int_21h_2fh()
8518: {
8519: process_t *process = msdos_process_info_get(current_psp);
8520:
8521: REG16(BX) = process->dta.w.l;
1.1.1.3 root 8522: SREG(ES) = process->dta.w.h;
8523: i386_load_segment_descriptor(ES);
1.1 root 8524: }
8525:
8526: inline void msdos_int_21h_30h()
8527: {
8528: // Version Flag / OEM
1.1.1.27 root 8529: if(REG8(AL) == 0x01) {
1.1.1.29 root 8530: #ifdef SUPPORT_HMA
8531: REG16(BX) = 0x0000;
8532: #else
8533: REG16(BX) = 0x1000; // DOS is in HMA
8534: #endif
1.1 root 8535: } else {
1.1.1.27 root 8536: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
8537: // but this is not correct on Windows 98 SE
8538: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
8539: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 8540: }
1.1.1.27 root 8541: REG16(CX) = 0x0000;
1.1.1.30 root 8542: REG8(AL) = dos_major_version; // 7
8543: REG8(AH) = dos_minor_version; // 10
1.1 root 8544: }
8545:
8546: inline void msdos_int_21h_31h()
8547: {
1.1.1.29 root 8548: try {
8549: msdos_mem_realloc(current_psp, REG16(DX), NULL);
8550: } catch(...) {
8551: // recover the broken mcb
8552: int mcb_seg = current_psp - 1;
8553: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 8554:
1.1.1.29 root 8555: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 8556: mcb->mz = 'M';
8557: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
8558:
1.1.1.29 root 8559: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.33 root 8560: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4));
1.1.1.29 root 8561: } else {
1.1.1.33 root 8562: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0);
1.1.1.29 root 8563: }
8564: } else {
8565: mcb->mz = 'Z';
1.1.1.30 root 8566: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 8567: }
8568: msdos_mem_realloc(current_psp, REG16(DX), NULL);
8569: }
1.1 root 8570: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
8571: }
8572:
8573: inline void msdos_int_21h_32h()
8574: {
8575: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
8576: UINT16 seg, ofs;
8577:
8578: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8579: REG8(AL) = 0;
1.1.1.3 root 8580: SREG(DS) = seg;
8581: i386_load_segment_descriptor(DS);
1.1 root 8582: REG16(BX) = ofs;
8583: } else {
8584: REG8(AL) = 0xff;
1.1.1.3 root 8585: m_CF = 1;
1.1 root 8586: }
8587: }
8588:
8589: inline void msdos_int_21h_33h()
8590: {
8591: char path[MAX_PATH];
8592:
8593: switch(REG8(AL)) {
8594: case 0x00:
1.1.1.33 root 8595: REG8(DL) = ctrl_break_checking;
1.1 root 8596: break;
8597: case 0x01:
1.1.1.33 root 8598: ctrl_break_checking = REG8(DL);
8599: break;
8600: case 0x02:
8601: {
8602: UINT8 old = ctrl_break_checking;
8603: ctrl_break_checking = REG8(DL);
8604: REG8(DL) = old;
8605: }
8606: break;
8607: case 0x03:
8608: case 0x04:
8609: // DOS 4.0+ - Unused
1.1 root 8610: break;
8611: case 0x05:
8612: GetSystemDirectory(path, MAX_PATH);
8613: if(path[0] >= 'a' && path[0] <= 'z') {
8614: REG8(DL) = path[0] - 'a' + 1;
8615: } else {
8616: REG8(DL) = path[0] - 'A' + 1;
8617: }
8618: break;
8619: case 0x06:
1.1.1.2 root 8620: // MS-DOS version (7.10)
1.1 root 8621: REG8(BL) = 7;
1.1.1.2 root 8622: REG8(BH) = 10;
1.1 root 8623: REG8(DL) = 0;
1.1.1.29 root 8624: #ifdef SUPPORT_HMA
8625: REG8(DH) = 0x00;
8626: #else
8627: REG8(DH) = 0x10; // DOS is in HMA
8628: #endif
1.1 root 8629: break;
1.1.1.6 root 8630: case 0x07:
8631: if(REG8(DL) == 0) {
8632: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
8633: } else if(REG8(DL) == 1) {
8634: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
8635: }
8636: break;
1.1 root 8637: default:
1.1.1.22 root 8638: 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 8639: REG16(AX) = 0x01;
1.1.1.3 root 8640: m_CF = 1;
1.1 root 8641: break;
8642: }
8643: }
8644:
1.1.1.23 root 8645: inline void msdos_int_21h_34h()
8646: {
8647: SREG(ES) = SDA_TOP >> 4;
8648: i386_load_segment_descriptor(ES);
8649: REG16(BX) = offsetof(sda_t, indos_flag);;
8650: }
8651:
1.1 root 8652: inline void msdos_int_21h_35h()
8653: {
8654: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 8655: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
8656: i386_load_segment_descriptor(ES);
1.1 root 8657: }
8658:
8659: inline void msdos_int_21h_36h()
8660: {
8661: struct _diskfree_t df = {0};
8662:
8663: if(_getdiskfree(REG8(DL), &df) == 0) {
8664: REG16(AX) = (UINT16)df.sectors_per_cluster;
8665: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 8666: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
8667: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 8668: } else {
8669: REG16(AX) = 0xffff;
8670: }
8671: }
8672:
8673: inline void msdos_int_21h_37h()
8674: {
1.1.1.22 root 8675: static UINT8 dev_flag = 0xff;
1.1 root 8676:
8677: switch(REG8(AL)) {
8678: case 0x00:
1.1.1.22 root 8679: {
8680: process_t *process = msdos_process_info_get(current_psp);
8681: REG8(AL) = 0x00;
8682: REG8(DL) = process->switchar;
8683: }
1.1 root 8684: break;
8685: case 0x01:
1.1.1.22 root 8686: {
8687: process_t *process = msdos_process_info_get(current_psp);
8688: REG8(AL) = 0x00;
8689: process->switchar = REG8(DL);
1.1.1.23 root 8690: msdos_sda_update(current_psp);
1.1.1.22 root 8691: }
8692: break;
8693: case 0x02:
8694: REG8(DL) = dev_flag;
8695: break;
8696: case 0x03:
8697: dev_flag = REG8(DL);
8698: break;
8699: case 0xd0:
8700: case 0xd1:
8701: case 0xd2:
8702: case 0xd3:
8703: case 0xd4:
8704: case 0xd5:
8705: case 0xd6:
8706: case 0xd7:
8707: case 0xdc:
8708: case 0xdd:
8709: case 0xde:
8710: case 0xdf:
8711: // diet ???
8712: REG16(AX) = 1;
1.1 root 8713: break;
8714: default:
1.1.1.22 root 8715: 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 8716: REG16(AX) = 1;
8717: break;
8718: }
8719: }
8720:
1.1.1.19 root 8721: int get_country_info(country_info_t *ci)
1.1.1.17 root 8722: {
8723: char LCdata[80];
8724:
1.1.1.19 root 8725: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 8726: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
8727: ci->currency_dec_digits = atoi(LCdata);
8728: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
8729: ci->currency_format = *LCdata - '0';
8730: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
8731: ci->date_format = *LCdata - '0';
8732: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
8733: memcpy(&ci->currency_symbol, LCdata, 4);
8734: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
8735: *ci->date_sep = *LCdata;
8736: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
8737: *ci->dec_sep = *LCdata;
8738: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
8739: *ci->list_sep = *LCdata;
8740: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
8741: *ci->thou_sep = *LCdata;
8742: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
8743: *ci->time_sep = *LCdata;
8744: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
8745: if(strchr(LCdata, 'H') != NULL) {
8746: ci->time_format = 1;
8747: }
1.1.1.27 root 8748: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 8749: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 8750: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
8751: return atoi(LCdata);
8752: }
8753:
1.1.1.14 root 8754: inline void msdos_int_21h_38h()
8755: {
8756: switch(REG8(AL)) {
8757: case 0x00:
1.1.1.19 root 8758: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 8759: break;
8760: default:
1.1.1.22 root 8761: 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 8762: REG16(AX) = 2;
8763: m_CF = 1;
8764: break;
8765: }
8766: }
8767:
1.1 root 8768: inline void msdos_int_21h_39h(int lfn)
8769: {
1.1.1.3 root 8770: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 8771: REG16(AX) = errno;
1.1.1.3 root 8772: m_CF = 1;
1.1 root 8773: }
8774: }
8775:
8776: inline void msdos_int_21h_3ah(int lfn)
8777: {
1.1.1.3 root 8778: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 8779: REG16(AX) = errno;
1.1.1.3 root 8780: m_CF = 1;
1.1 root 8781: }
8782: }
8783:
8784: inline void msdos_int_21h_3bh(int lfn)
8785: {
1.1.1.3 root 8786: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 8787: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 8788: m_CF = 1;
1.1 root 8789: }
8790: }
8791:
8792: inline void msdos_int_21h_3ch()
8793: {
1.1.1.3 root 8794: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 8795: int attr = GetFileAttributes(path);
1.1.1.29 root 8796: int fd = -1, c;
1.1.1.11 root 8797: UINT16 info;
1.1 root 8798:
1.1.1.11 root 8799: if(msdos_is_con_path(path)) {
8800: fd = _open("CON", _O_WRONLY | _O_BINARY);
8801: info = 0x80d3;
1.1.1.29 root 8802: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8803: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), _O_WRONLY | _O_BINARY)) == -1) {
8804: fd = _open("NUL", _O_WRONLY | _O_BINARY);
8805: }
1.1.1.14 root 8806: info = 0x80d3;
1.1.1.29 root 8807: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8808: fd = _open("NUL", _O_WRONLY | _O_BINARY);
8809: info = 0x80d3;
1.1 root 8810: } else {
8811: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 8812: info = msdos_drive_number(path);
1.1 root 8813: }
8814: if(fd != -1) {
8815: if(attr == -1) {
8816: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
8817: }
8818: SetFileAttributes(path, attr);
8819: REG16(AX) = fd;
1.1.1.11 root 8820: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 8821: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8822: } else {
8823: REG16(AX) = errno;
1.1.1.3 root 8824: m_CF = 1;
1.1 root 8825: }
8826: }
8827:
8828: inline void msdos_int_21h_3dh()
8829: {
1.1.1.3 root 8830: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 8831: int mode = REG8(AL) & 0x03;
1.1.1.29 root 8832: int fd = -1, c;
1.1.1.11 root 8833: UINT16 info;
1.1 root 8834:
8835: if(mode < 0x03) {
1.1.1.11 root 8836: if(msdos_is_con_path(path)) {
1.1.1.13 root 8837: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 8838: info = 0x80d3;
1.1.1.29 root 8839: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8840: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
8841: fd = msdos_open("NUL", file_mode[mode].mode);
8842: }
1.1.1.14 root 8843: info = 0x80d3;
1.1.1.29 root 8844: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8845: fd = msdos_open("NUL", file_mode[mode].mode);
8846: info = 0x80d3;
1.1.1.11 root 8847: } else {
1.1.1.13 root 8848: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 8849: info = msdos_drive_number(path);
8850: }
1.1 root 8851: if(fd != -1) {
8852: REG16(AX) = fd;
1.1.1.11 root 8853: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 8854: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8855: } else {
8856: REG16(AX) = errno;
1.1.1.3 root 8857: m_CF = 1;
1.1 root 8858: }
8859: } else {
8860: REG16(AX) = 0x0c;
1.1.1.3 root 8861: m_CF = 1;
1.1 root 8862: }
8863: }
8864:
8865: inline void msdos_int_21h_3eh()
8866: {
8867: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8868: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8869:
1.1.1.20 root 8870: if(fd < process->max_files && file_handler[fd].valid) {
8871: _close(fd);
8872: msdos_file_handler_close(fd);
8873: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 8874: } else {
8875: REG16(AX) = 0x06;
1.1.1.3 root 8876: m_CF = 1;
1.1 root 8877: }
8878: }
8879:
1.1.1.35! root 8880: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID)
! 8881: {
! 8882: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
! 8883: int max = REG16(CX);
! 8884: int p = 0;
! 8885:
! 8886: while(max > p) {
! 8887: int chr = msdos_getch();
! 8888:
! 8889: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
! 8890: p = 0;
! 8891: buf[p++] = 0x0d;
! 8892: if(max > p) {
! 8893: buf[p++] = 0x0a;
! 8894: }
! 8895: msdos_putch(0x03);
! 8896: msdos_putch(0x0d);
! 8897: msdos_putch(0x0a);
! 8898: break;
! 8899: } else if(ctrl_break_pressed) {
! 8900: // skip this byte
! 8901: } else if(chr == 0x00) {
! 8902: // skip 2nd byte
! 8903: msdos_getch();
! 8904: } else if(chr == 0x0d) {
! 8905: // carriage return
! 8906: buf[p++] = 0x0d;
! 8907: if(max > p) {
! 8908: buf[p++] = 0x0a;
! 8909: }
! 8910: msdos_putch('\n');
! 8911: break;
! 8912: } else if(chr == 0x08) {
! 8913: // back space
! 8914: if(p > 0) {
! 8915: p--;
! 8916: if(msdos_ctrl_code_check(buf[p])) {
! 8917: msdos_putch(0x08);
! 8918: msdos_putch(0x08);
! 8919: msdos_putch(0x20);
! 8920: msdos_putch(0x20);
! 8921: msdos_putch(0x08);
! 8922: msdos_putch(0x08);
! 8923: } else {
! 8924: msdos_putch(0x08);
! 8925: msdos_putch(0x20);
! 8926: msdos_putch(0x08);
! 8927: }
! 8928: }
! 8929: } else if(chr == 0x1b) {
! 8930: // escape
! 8931: while(p > 0) {
! 8932: p--;
! 8933: if(msdos_ctrl_code_check(buf[p])) {
! 8934: msdos_putch(0x08);
! 8935: msdos_putch(0x08);
! 8936: msdos_putch(0x20);
! 8937: msdos_putch(0x20);
! 8938: msdos_putch(0x08);
! 8939: msdos_putch(0x08);
! 8940: } else {
! 8941: msdos_putch(0x08);
! 8942: msdos_putch(0x20);
! 8943: msdos_putch(0x08);
! 8944: }
! 8945: }
! 8946: } else {
! 8947: buf[p++] = chr;
! 8948: msdos_putch(chr);
! 8949: }
! 8950: }
! 8951: REG16(AX) = p;
! 8952:
! 8953: #ifdef USE_SERVICE_THREAD
! 8954: service_exit = true;
! 8955: #endif
! 8956: return(0);
! 8957: }
! 8958:
1.1 root 8959: inline void msdos_int_21h_3fh()
8960: {
8961: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8962: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8963:
1.1.1.20 root 8964: if(fd < process->max_files && file_handler[fd].valid) {
8965: if(file_mode[file_handler[fd].mode].in) {
8966: if(file_handler[fd].atty) {
1.1 root 8967: // BX is stdin or is redirected to stdin
1.1.1.35! root 8968: if(REG16(CX) != 0) {
! 8969: #ifdef USE_SERVICE_THREAD
! 8970: start_service_loop(msdos_int_21h_3fh_thread);
! 8971: #else
! 8972: msdos_int_21h_3fh_thread(NULL);
! 8973: REQUEST_HARDWRE_UPDATE();
! 8974: #endif
! 8975: } else {
! 8976: REG16(AX) = 0;
1.1 root 8977: }
8978: } else {
1.1.1.20 root 8979: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 8980: }
8981: } else {
8982: REG16(AX) = 0x05;
1.1.1.3 root 8983: m_CF = 1;
1.1 root 8984: }
8985: } else {
8986: REG16(AX) = 0x06;
1.1.1.3 root 8987: m_CF = 1;
1.1 root 8988: }
8989: }
8990:
8991: inline void msdos_int_21h_40h()
8992: {
8993: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8994: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8995:
1.1.1.20 root 8996: if(fd < process->max_files && file_handler[fd].valid) {
8997: if(file_mode[file_handler[fd].mode].out) {
1.1 root 8998: if(REG16(CX)) {
1.1.1.20 root 8999: if(file_handler[fd].atty) {
1.1 root 9000: // BX is stdout/stderr or is redirected to stdout
9001: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 9002: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 9003: }
9004: REG16(AX) = REG16(CX);
9005: } else {
1.1.1.20 root 9006: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 9007: }
9008: } else {
1.1.1.20 root 9009: UINT32 pos = _tell(fd);
9010: _lseek(fd, 0, SEEK_END);
9011: UINT32 size = _tell(fd);
1.1.1.12 root 9012: if(pos < size) {
1.1.1.20 root 9013: _lseek(fd, pos, SEEK_SET);
9014: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 9015: } else {
9016: for(UINT32 i = size; i < pos; i++) {
9017: UINT8 tmp = 0;
1.1.1.23 root 9018: msdos_write(fd, &tmp, 1);
1.1.1.12 root 9019: }
1.1.1.20 root 9020: _lseek(fd, pos, SEEK_SET);
1.1 root 9021: }
1.1.1.23 root 9022: REG16(AX) = 0;
1.1 root 9023: }
9024: } else {
9025: REG16(AX) = 0x05;
1.1.1.3 root 9026: m_CF = 1;
1.1 root 9027: }
9028: } else {
9029: REG16(AX) = 0x06;
1.1.1.3 root 9030: m_CF = 1;
1.1 root 9031: }
9032: }
9033:
9034: inline void msdos_int_21h_41h(int lfn)
9035: {
1.1.1.3 root 9036: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 9037: REG16(AX) = errno;
1.1.1.3 root 9038: m_CF = 1;
1.1 root 9039: }
9040: }
9041:
9042: inline void msdos_int_21h_42h()
9043: {
9044: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9045: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9046:
1.1.1.20 root 9047: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 9048: if(REG8(AL) < 0x03) {
1.1.1.35! root 9049: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 9050: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
9051: UINT32 pos = _tell(fd);
1.1 root 9052: REG16(AX) = pos & 0xffff;
9053: REG16(DX) = (pos >> 16);
9054: } else {
9055: REG16(AX) = 0x01;
1.1.1.3 root 9056: m_CF = 1;
1.1 root 9057: }
9058: } else {
9059: REG16(AX) = 0x06;
1.1.1.3 root 9060: m_CF = 1;
1.1 root 9061: }
9062: }
9063:
9064: inline void msdos_int_21h_43h(int lfn)
9065: {
1.1.1.3 root 9066: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 9067: int attr;
9068:
1.1.1.14 root 9069: if(!lfn && REG8(AL) > 2) {
9070: REG16(AX) = 0x01;
9071: m_CF = 1;
9072: return;
9073: }
9074: switch(REG8(lfn ? BL : AL)) {
1.1 root 9075: case 0x00:
9076: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 9077: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
9078: } else {
9079: REG16(AX) = (UINT16)GetLastError();
9080: m_CF = 1;
9081: }
9082: break;
9083: case 0x01:
9084: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
9085: REG16(AX) = (UINT16)GetLastError();
9086: m_CF = 1;
9087: }
9088: break;
9089: case 0x02:
9090: {
9091: DWORD size = GetCompressedFileSize(path, NULL);
9092: if(size != INVALID_FILE_SIZE) {
9093: if(size != 0 && size == GetFileSize(path, NULL)) {
9094: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
9095: // this isn't correct if the file is in the NTFS MFT
9096: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
9097: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
9098: }
9099: }
9100: REG16(AX) = LOWORD(size);
9101: REG16(DX) = HIWORD(size);
9102: } else {
9103: REG16(AX) = (UINT16)GetLastError();
9104: m_CF = 1;
1.1 root 9105: }
1.1.1.14 root 9106: }
9107: break;
9108: case 0x03:
9109: case 0x05:
9110: case 0x07:
9111: {
9112: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9113: if(hFile != INVALID_HANDLE_VALUE) {
9114: FILETIME local, time;
9115: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
9116: if(REG8(BL) == 7) {
9117: ULARGE_INTEGER hund;
9118: hund.LowPart = local.dwLowDateTime;
9119: hund.HighPart = local.dwHighDateTime;
9120: hund.QuadPart += REG16(SI) * 100000;
9121: local.dwLowDateTime = hund.LowPart;
9122: local.dwHighDateTime = hund.HighPart;
9123: }
9124: LocalFileTimeToFileTime(&local, &time);
9125: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
9126: REG8(BL) == 0x05 ? &time : NULL,
9127: REG8(BL) == 0x03 ? &time : NULL)) {
9128: REG16(AX) = (UINT16)GetLastError();
9129: m_CF = 1;
9130: }
9131: CloseHandle(hFile);
9132: } else {
9133: REG16(AX) = (UINT16)GetLastError();
9134: m_CF = 1;
1.1 root 9135: }
1.1.1.14 root 9136: }
9137: break;
9138: case 0x04:
9139: case 0x06:
9140: case 0x08:
9141: {
9142: WIN32_FILE_ATTRIBUTE_DATA fad;
9143: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
9144: FILETIME *time, local;
9145: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
9146: 0x06 ? &fad.ftLastAccessTime :
9147: &fad.ftCreationTime;
9148: FileTimeToLocalFileTime(time, &local);
9149: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
9150: if(REG8(BL) == 0x08) {
9151: ULARGE_INTEGER hund;
9152: hund.LowPart = local.dwLowDateTime;
9153: hund.HighPart = local.dwHighDateTime;
9154: hund.QuadPart /= 100000;
9155: REG16(SI) = (UINT16)(hund.QuadPart % 200);
9156: }
9157: } else {
9158: REG16(AX) = (UINT16)GetLastError();
9159: m_CF = 1;
1.1 root 9160: }
1.1.1.14 root 9161: }
9162: break;
9163: default:
1.1.1.22 root 9164: 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 9165: REG16(AX) = 0x01;
9166: m_CF = 1;
9167: break;
9168: }
9169: }
9170:
9171: inline void msdos_int_21h_44h()
9172: {
1.1.1.22 root 9173: static UINT16 iteration_count = 0;
9174:
1.1.1.20 root 9175: process_t *process = msdos_process_info_get(current_psp);
9176: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9177:
1.1.1.14 root 9178: UINT32 val = DRIVE_NO_ROOT_DIR;
9179:
9180: switch(REG8(AL)) {
9181: case 0x00:
9182: case 0x01:
9183: case 0x02:
9184: case 0x03:
9185: case 0x04:
9186: case 0x05:
9187: case 0x06:
9188: case 0x07:
1.1.1.20 root 9189: if(fd >= process->max_files || !file_handler[fd].valid) {
9190: REG16(AX) = 0x06;
9191: m_CF = 1;
9192: return;
1.1.1.14 root 9193: }
9194: break;
9195: case 0x08:
9196: case 0x09:
9197: if(REG8(BL) >= ('Z' - 'A' + 1)) {
9198: // invalid drive number
9199: REG16(AX) = 0x0f;
9200: m_CF = 1;
9201: return;
9202: } else {
9203: if(REG8(BL) == 0) {
9204: val = GetDriveType(NULL);
9205: } else {
9206: char tmp[8];
9207: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
9208: val = GetDriveType(tmp);
9209: }
9210: if(val == DRIVE_NO_ROOT_DIR) {
9211: // no drive
9212: REG16(AX) = 0x0f;
9213: m_CF = 1;
9214: return;
1.1 root 9215: }
9216: }
9217: break;
9218: }
9219: switch(REG8(AL)) {
9220: case 0x00: // get ioctrl data
1.1.1.20 root 9221: REG16(DX) = file_handler[fd].info;
1.1 root 9222: break;
9223: case 0x01: // set ioctrl data
1.1.1.20 root 9224: file_handler[fd].info |= REG8(DL);
1.1 root 9225: break;
9226: case 0x02: // recv from character device
9227: case 0x03: // send to character device
9228: case 0x04: // recv from block device
9229: case 0x05: // send to block device
9230: REG16(AX) = 0x05;
1.1.1.3 root 9231: m_CF = 1;
1.1 root 9232: break;
9233: case 0x06: // get read status
1.1.1.20 root 9234: if(file_mode[file_handler[fd].mode].in) {
9235: if(file_handler[fd].atty) {
1.1.1.14 root 9236: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 9237: } else {
1.1.1.20 root 9238: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 9239: }
1.1.1.14 root 9240: } else {
9241: REG8(AL) = 0x00;
1.1 root 9242: }
9243: break;
9244: case 0x07: // get write status
1.1.1.20 root 9245: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 9246: REG8(AL) = 0xff;
9247: } else {
9248: REG8(AL) = 0x00;
1.1 root 9249: }
9250: break;
9251: case 0x08: // check removable drive
1.1.1.14 root 9252: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
9253: // removable drive
9254: REG16(AX) = 0x00;
1.1 root 9255: } else {
1.1.1.14 root 9256: // fixed drive
9257: REG16(AX) = 0x01;
1.1 root 9258: }
9259: break;
9260: case 0x09: // check remote drive
1.1.1.14 root 9261: if(val == DRIVE_REMOTE) {
9262: // remote drive
9263: REG16(DX) = 0x1000;
1.1 root 9264: } else {
1.1.1.14 root 9265: // local drive
9266: REG16(DX) = 0x00;
1.1 root 9267: }
9268: break;
1.1.1.21 root 9269: case 0x0a: // check remote handle
9270: REG16(DX) = 0x00; // FIXME
9271: break;
1.1 root 9272: case 0x0b: // set retry count
9273: break;
1.1.1.22 root 9274: case 0x0c: // generic character device request
9275: if(REG8(CL) == 0x45) {
9276: // set iteration (retry) count
9277: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
9278: } else if(REG8(CL) == 0x4a) {
9279: // select code page
9280: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
9281: msdos_nls_tables_update();
9282: } else if(REG8(CL) == 0x65) {
9283: // get iteration (retry) count
9284: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
9285: } else if(REG8(CL) == 0x6a) {
9286: // query selected code page
9287: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
9288: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
9289:
9290: CPINFO info;
9291: GetCPInfo(active_code_page, &info);
9292:
9293: if(info.MaxCharSize != 1) {
9294: for(int i = 0;; i++) {
9295: UINT8 lo = info.LeadByte[2 * i + 0];
9296: UINT8 hi = info.LeadByte[2 * i + 1];
9297:
9298: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
9299: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
9300: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
9301:
9302: if(lo == 0 && hi == 0) {
9303: break;
9304: }
9305: }
9306: }
9307: } else if(REG8(CL) == 0x7f) {
9308: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
9309: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
9310: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
9311: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
9312: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
9313: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
9314: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
9315: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
9316: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
9317: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
9318: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
9319: } else {
9320: 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));
9321: REG16(AX) = 0x01; // invalid function
9322: m_CF = 1;
9323: }
9324: break;
9325: case 0x0d: // generic block device request
9326: if(REG8(CL) == 0x40) {
9327: // set device parameters
9328: } else if(REG8(CL) == 0x46) {
9329: // set volume serial number
9330: } else if(REG8(CL) == 0x4a) {
9331: // lock logical volume
9332: } else if(REG8(CL) == 0x4b) {
9333: // lock physical volume
9334: } else if(REG8(CL) == 0x60) {
9335: // get device parameters
9336: char dev[] = "\\\\.\\A:";
9337: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
9338:
9339: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9340: if(hFile != INVALID_HANDLE_VALUE) {
9341: DISK_GEOMETRY geo;
9342: DWORD dwSize;
9343: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
9344: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
9345: switch(geo.MediaType) {
9346: case F5_360_512:
9347: case F5_320_512:
9348: case F5_320_1024:
9349: case F5_180_512:
9350: case F5_160_512:
9351: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
9352: break;
9353: case F5_1Pt2_512:
9354: case F3_1Pt2_512:
9355: case F3_1Pt23_1024:
9356: case F5_1Pt23_1024:
9357: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
9358: break;
9359: case F3_720_512:
9360: case F3_640_512:
9361: case F5_640_512:
9362: case F5_720_512:
9363: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
9364: break;
9365: case F8_256_128:
9366: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
9367: break;
9368: case FixedMedia:
9369: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
9370: break;
9371: case F3_1Pt44_512:
9372: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
9373: break;
9374: case F3_2Pt88_512:
9375: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
9376: break;
9377: default:
9378: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
9379: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
9380: break;
9381: }
9382: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
9383: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
9384: switch(geo.MediaType) {
9385: case F5_360_512:
9386: case F5_320_512:
9387: case F5_320_1024:
9388: case F5_180_512:
9389: case F5_160_512:
9390: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
9391: break;
9392: default:
9393: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
9394: break;
9395: }
9396: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
9397: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
9398: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
9399: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
9400: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
9401: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
9402: switch(geo.MediaType) {
9403: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
9404: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
9405: break;
9406: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
9407: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
9408: break;
9409: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
9410: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
9411: break;
9412: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
9413: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
9414: break;
9415: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
9416: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
9417: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
9418: break;
9419: case FixedMedia: // hard disk
9420: case RemovableMedia:
9421: case Unknown:
9422: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
9423: break;
9424: default:
9425: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
9426: break;
9427: }
9428: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
9429: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
9430: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
9431: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
9432: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
9433: // 21h BYTE device type
9434: // 22h WORD device attributes (removable or not, etc)
9435: } else {
9436: REG16(AX) = 0x0f; // invalid drive
9437: m_CF = 1;
9438: }
9439: CloseHandle(hFile);
9440: } else {
9441: REG16(AX) = 0x0f; // invalid drive
9442: m_CF = 1;
9443: }
9444: } else if(REG8(CL) == 0x66) {
9445: // get volume serial number
9446: char path[] = "A:\\";
9447: char volume_label[MAX_PATH];
9448: DWORD serial_number = 0;
9449: char file_system[MAX_PATH];
9450:
9451: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
9452:
9453: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
9454: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
9455: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
9456: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
9457: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
9458: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
9459: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
9460: } else {
9461: REG16(AX) = 0x0f; // invalid drive
9462: m_CF = 1;
9463: }
9464: } else if(REG8(CL) == 0x67) {
9465: // get access flag
9466: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
9467: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
9468: } else if(REG8(CL) == 0x68) {
9469: // sense media type
9470: char dev[64];
9471: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9472:
9473: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9474: if(hFile != INVALID_HANDLE_VALUE) {
9475: DISK_GEOMETRY geo;
9476: DWORD dwSize;
9477: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
9478: switch(geo.MediaType) {
9479: case F3_720_512:
9480: case F5_720_512:
9481: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9482: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
9483: break;
9484: case F3_1Pt44_512:
9485: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9486: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
9487: break;
9488: case F3_2Pt88_512:
9489: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9490: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
9491: break;
9492: default:
9493: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
9494: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
9495: break;
9496: }
9497: } else {
9498: REG16(AX) = 0x0f; // invalid drive
9499: m_CF = 1;
9500: }
9501: CloseHandle(hFile);
9502: } else {
9503: REG16(AX) = 0x0f; // invalid drive
9504: m_CF = 1;
9505: }
9506: } else if(REG8(CL) == 0x6a) {
9507: // unlock logical volume
9508: } else if(REG8(CL) == 0x6b) {
9509: // unlock physical volume
9510: } else {
9511: 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));
9512: REG16(AX) = 0x01; // invalid function
9513: m_CF = 1;
9514: }
9515: break;
9516: case 0x0e: // get logical drive map
9517: {
9518: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9519: if(!(GetLogicalDrives() & bits)) {
9520: REG16(AX) = 0x0f; // invalid drive
9521: m_CF = 1;
9522: } else {
9523: REG8(AL) = 0;
9524: }
9525: }
9526: break;
9527: case 0x0f: // set logical drive map
9528: {
9529: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9530: if(!(GetLogicalDrives() & bits)) {
9531: REG16(AX) = 0x0f; // invalid drive
9532: m_CF = 1;
9533: }
9534: }
9535: break;
9536: case 0x10: // query generic ioctrl capability (handle)
9537: switch(REG8(CL)) {
9538: case 0x45:
9539: case 0x4a:
9540: case 0x65:
9541: case 0x6a:
9542: case 0x7f:
9543: REG16(AX) = 0x0000; // supported
9544: break;
9545: default:
9546: REG8(AL) = 0x01; // ioctl capability not available
9547: m_CF = 1;
9548: break;
9549: }
9550: break;
9551: case 0x11: // query generic ioctrl capability (drive)
9552: switch(REG8(CL)) {
9553: case 0x40:
9554: case 0x46:
9555: case 0x4a:
9556: case 0x4b:
9557: case 0x60:
9558: case 0x66:
9559: case 0x67:
9560: case 0x68:
9561: case 0x6a:
9562: case 0x6b:
9563: REG16(AX) = 0x0000; // supported
9564: break;
9565: default:
9566: REG8(AL) = 0x01; // ioctl capability not available
9567: m_CF = 1;
9568: break;
9569: }
9570: break;
9571: case 0x12: // determine dos type
9572: case 0x51: // concurrent dos v3.2+ - installation check
9573: case 0x52: // determine dos type/get dr dos versuin
9574: REG16(AX) = 0x01; // this is not DR-DOS
9575: m_CF = 1;
9576: break;
1.1 root 9577: default:
1.1.1.22 root 9578: 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 9579: REG16(AX) = 0x01;
1.1.1.3 root 9580: m_CF = 1;
1.1 root 9581: break;
9582: }
9583: }
9584:
9585: inline void msdos_int_21h_45h()
9586: {
9587: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9588: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9589:
1.1.1.20 root 9590: if(fd < process->max_files && file_handler[fd].valid) {
9591: int dup_fd = _dup(fd);
9592: if(dup_fd != -1) {
9593: REG16(AX) = dup_fd;
9594: msdos_file_handler_dup(dup_fd, fd, current_psp);
9595: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
9596: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 9597: } else {
9598: REG16(AX) = errno;
1.1.1.3 root 9599: m_CF = 1;
1.1 root 9600: }
9601: } else {
9602: REG16(AX) = 0x06;
1.1.1.3 root 9603: m_CF = 1;
1.1 root 9604: }
9605: }
9606:
9607: inline void msdos_int_21h_46h()
9608: {
9609: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9610: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9611: int dup_fd = REG16(CX);
9612: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 9613:
1.1.1.20 root 9614: if(REG16(BX) == REG16(CX)) {
9615: REG16(AX) = 0x06;
9616: m_CF = 1;
9617: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
9618: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
9619: _close(tmp_fd);
9620: msdos_file_handler_close(tmp_fd);
9621: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
9622: }
9623: if(_dup2(fd, dup_fd) != -1) {
9624: msdos_file_handler_dup(dup_fd, fd, current_psp);
9625: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
9626: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 9627: } else {
9628: REG16(AX) = errno;
1.1.1.3 root 9629: m_CF = 1;
1.1 root 9630: }
9631: } else {
9632: REG16(AX) = 0x06;
1.1.1.3 root 9633: m_CF = 1;
1.1 root 9634: }
9635: }
9636:
9637: inline void msdos_int_21h_47h(int lfn)
9638: {
9639: char path[MAX_PATH];
9640:
9641: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
9642: if(path[1] == ':') {
9643: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 9644: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 9645: } else {
1.1.1.3 root 9646: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 9647: }
9648: } else {
9649: REG16(AX) = errno;
1.1.1.3 root 9650: m_CF = 1;
1.1 root 9651: }
9652: }
9653:
9654: inline void msdos_int_21h_48h()
9655: {
1.1.1.19 root 9656: int seg, umb_linked;
1.1 root 9657:
1.1.1.8 root 9658: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 9659: // unlink umb not to allocate memory in umb
9660: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
9661: msdos_mem_unlink_umb();
9662: }
1.1.1.8 root 9663: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
9664: REG16(AX) = seg;
9665: } else {
9666: REG16(AX) = 0x08;
9667: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
9668: m_CF = 1;
9669: }
1.1.1.19 root 9670: if(umb_linked != 0) {
9671: msdos_mem_link_umb();
9672: }
1.1.1.8 root 9673: } else if((malloc_strategy & 0xf0) == 0x40) {
9674: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
9675: REG16(AX) = seg;
9676: } else {
9677: REG16(AX) = 0x08;
9678: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9679: m_CF = 1;
9680: }
9681: } else if((malloc_strategy & 0xf0) == 0x80) {
9682: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
9683: REG16(AX) = seg;
9684: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
9685: REG16(AX) = seg;
9686: } else {
9687: REG16(AX) = 0x08;
9688: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
9689: m_CF = 1;
9690: }
1.1 root 9691: }
9692: }
9693:
9694: inline void msdos_int_21h_49h()
9695: {
1.1.1.14 root 9696: int mcb_seg = SREG(ES) - 1;
9697: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9698:
9699: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9700: msdos_mem_free(SREG(ES));
9701: } else {
1.1.1.33 root 9702: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 9703: m_CF = 1;
9704: }
1.1 root 9705: }
9706:
9707: inline void msdos_int_21h_4ah()
9708: {
1.1.1.14 root 9709: int mcb_seg = SREG(ES) - 1;
9710: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 9711: int max_paragraphs;
9712:
1.1.1.14 root 9713: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9714: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
9715: REG16(AX) = 0x08;
9716: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
9717: m_CF = 1;
9718: }
9719: } else {
1.1.1.33 root 9720: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 9721: m_CF = 1;
1.1 root 9722: }
9723: }
9724:
9725: inline void msdos_int_21h_4bh()
9726: {
1.1.1.3 root 9727: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
9728: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 9729:
9730: switch(REG8(AL)) {
9731: case 0x00:
9732: case 0x01:
9733: if(msdos_process_exec(command, param, REG8(AL))) {
9734: REG16(AX) = 0x02;
1.1.1.3 root 9735: m_CF = 1;
1.1 root 9736: }
9737: break;
1.1.1.14 root 9738: case 0x03:
9739: {
9740: int fd;
9741: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
9742: REG16(AX) = 0x02;
9743: m_CF = 1;
9744: break;
9745: }
9746: int size = _read(fd, file_buffer, sizeof(file_buffer));
9747: _close(fd);
9748:
9749: UINT16 *overlay = (UINT16 *)param;
9750:
9751: // check exe header
9752: exe_header_t *header = (exe_header_t *)file_buffer;
9753: int header_size = 0;
9754: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
9755: header_size = header->header_size * 16;
9756: // relocation
9757: int start_seg = overlay[1];
9758: for(int i = 0; i < header->relocations; i++) {
9759: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
9760: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
9761: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
9762: }
9763: }
9764: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
9765: }
9766: break;
1.1 root 9767: default:
1.1.1.22 root 9768: 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 9769: REG16(AX) = 0x01;
1.1.1.3 root 9770: m_CF = 1;
1.1 root 9771: break;
9772: }
9773: }
9774:
9775: inline void msdos_int_21h_4ch()
9776: {
9777: msdos_process_terminate(current_psp, REG8(AL), 1);
9778: }
9779:
9780: inline void msdos_int_21h_4dh()
9781: {
9782: REG16(AX) = retval;
9783: }
9784:
9785: inline void msdos_int_21h_4eh()
9786: {
9787: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9788: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9789: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 9790: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 9791: WIN32_FIND_DATA fd;
9792:
1.1.1.14 root 9793: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
9794: find->find_magic = FIND_MAGIC;
9795: find->dta_index = dtainfo - dtalist;
1.1 root 9796: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 9797: dtainfo->allowable_mask = REG8(CL);
9798: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 9799:
1.1.1.14 root 9800: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
9801: dtainfo->allowable_mask &= ~8;
1.1 root 9802: }
1.1.1.14 root 9803: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
9804: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9805: !msdos_find_file_has_8dot3name(&fd)) {
9806: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9807: FindClose(dtainfo->find_handle);
9808: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9809: break;
9810: }
9811: }
9812: }
1.1.1.13 root 9813: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9814: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
9815: msdos_find_file_conv_local_time(&fd);
9816: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
9817: find->size = fd.nFileSizeLow;
1.1.1.13 root 9818: strcpy(find->name, msdos_short_name(&fd));
1.1 root 9819: REG16(AX) = 0;
1.1.1.14 root 9820: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9821: find->attrib = 8;
9822: find->size = 0;
9823: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 9824: dtainfo->allowable_mask &= ~8;
1.1 root 9825: REG16(AX) = 0;
9826: } else {
9827: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 9828: m_CF = 1;
1.1 root 9829: }
9830: }
9831:
9832: inline void msdos_int_21h_4fh()
9833: {
9834: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9835: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9836: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 9837: WIN32_FIND_DATA fd;
9838:
1.1.1.14 root 9839: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
9840: REG16(AX) = 0x12;
9841: m_CF = 1;
9842: return;
9843: }
9844: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 9845: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9846: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 9847: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9848: !msdos_find_file_has_8dot3name(&fd)) {
9849: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9850: FindClose(dtainfo->find_handle);
9851: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9852: break;
9853: }
9854: }
9855: } else {
1.1.1.13 root 9856: FindClose(dtainfo->find_handle);
9857: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9858: }
9859: }
1.1.1.13 root 9860: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9861: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
9862: msdos_find_file_conv_local_time(&fd);
9863: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
9864: find->size = fd.nFileSizeLow;
1.1.1.13 root 9865: strcpy(find->name, msdos_short_name(&fd));
1.1 root 9866: REG16(AX) = 0;
1.1.1.14 root 9867: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9868: find->attrib = 8;
9869: find->size = 0;
9870: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 9871: dtainfo->allowable_mask &= ~8;
1.1 root 9872: REG16(AX) = 0;
9873: } else {
9874: REG16(AX) = 0x12;
1.1.1.3 root 9875: m_CF = 1;
1.1 root 9876: }
9877: }
9878:
9879: inline void msdos_int_21h_50h()
9880: {
1.1.1.8 root 9881: if(current_psp != REG16(BX)) {
9882: process_t *process = msdos_process_info_get(current_psp);
9883: if(process != NULL) {
9884: process->psp = REG16(BX);
9885: }
9886: current_psp = REG16(BX);
1.1.1.23 root 9887: msdos_sda_update(current_psp);
1.1.1.8 root 9888: }
1.1 root 9889: }
9890:
9891: inline void msdos_int_21h_51h()
9892: {
9893: REG16(BX) = current_psp;
9894: }
9895:
9896: inline void msdos_int_21h_52h()
9897: {
1.1.1.25 root 9898: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 9899: i386_load_segment_descriptor(ES);
1.1.1.25 root 9900: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 9901: }
9902:
9903: inline void msdos_int_21h_54h()
9904: {
9905: process_t *process = msdos_process_info_get(current_psp);
9906:
9907: REG8(AL) = process->verify;
9908: }
9909:
9910: inline void msdos_int_21h_55h()
9911: {
9912: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
9913:
9914: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
9915: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
9916: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
9917: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
9918: psp->parent_psp = current_psp;
9919: }
9920:
9921: inline void msdos_int_21h_56h(int lfn)
9922: {
9923: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 9924: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
9925: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 9926:
9927: if(rename(src, dst)) {
9928: REG16(AX) = errno;
1.1.1.3 root 9929: m_CF = 1;
1.1 root 9930: }
9931: }
9932:
9933: inline void msdos_int_21h_57h()
9934: {
9935: FILETIME time, local;
1.1.1.14 root 9936: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 9937: HANDLE hHandle;
1.1 root 9938:
1.1.1.21 root 9939: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 9940: REG16(AX) = (UINT16)GetLastError();
9941: m_CF = 1;
9942: return;
9943: }
9944: ctime = atime = mtime = NULL;
9945:
1.1 root 9946: switch(REG8(AL)) {
9947: case 0x00:
1.1.1.6 root 9948: case 0x01:
1.1.1.14 root 9949: mtime = &time;
1.1.1.6 root 9950: break;
9951: case 0x04:
9952: case 0x05:
1.1.1.14 root 9953: atime = &time;
1.1 root 9954: break;
1.1.1.6 root 9955: case 0x06:
9956: case 0x07:
1.1.1.14 root 9957: ctime = &time;
9958: break;
9959: default:
1.1.1.22 root 9960: 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 9961: REG16(AX) = 0x01;
9962: m_CF = 1;
9963: return;
9964: }
9965: if(REG8(AL) & 1) {
1.1 root 9966: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
9967: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 9968: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 9969: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 9970: m_CF = 1;
1.1 root 9971: }
1.1.1.14 root 9972: } else {
1.1.1.21 root 9973: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 9974: // assume a device and use the current time
9975: GetSystemTimeAsFileTime(&time);
9976: }
9977: FileTimeToLocalFileTime(&time, &local);
9978: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 9979: }
9980: }
9981:
9982: inline void msdos_int_21h_58h()
9983: {
9984: switch(REG8(AL)) {
9985: case 0x00:
1.1.1.7 root 9986: REG16(AX) = malloc_strategy;
9987: break;
9988: case 0x01:
1.1.1.24 root 9989: // switch(REG16(BX)) {
9990: switch(REG8(BL)) {
1.1.1.7 root 9991: case 0x0000:
9992: case 0x0001:
9993: case 0x0002:
9994: case 0x0040:
9995: case 0x0041:
9996: case 0x0042:
9997: case 0x0080:
9998: case 0x0081:
9999: case 0x0082:
10000: malloc_strategy = REG16(BX);
1.1.1.23 root 10001: msdos_sda_update(current_psp);
1.1.1.7 root 10002: break;
10003: default:
1.1.1.22 root 10004: 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 10005: REG16(AX) = 0x01;
10006: m_CF = 1;
10007: break;
10008: }
10009: break;
10010: case 0x02:
1.1.1.19 root 10011: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 10012: break;
10013: case 0x03:
1.1.1.24 root 10014: // switch(REG16(BX)) {
10015: switch(REG8(BL)) {
1.1.1.7 root 10016: case 0x0000:
1.1.1.19 root 10017: msdos_mem_unlink_umb();
10018: break;
1.1.1.7 root 10019: case 0x0001:
1.1.1.19 root 10020: msdos_mem_link_umb();
1.1.1.7 root 10021: break;
10022: default:
1.1.1.22 root 10023: 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 10024: REG16(AX) = 0x01;
10025: m_CF = 1;
10026: break;
10027: }
1.1 root 10028: break;
10029: default:
1.1.1.22 root 10030: 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 10031: REG16(AX) = 0x01;
1.1.1.3 root 10032: m_CF = 1;
1.1 root 10033: break;
10034: }
10035: }
10036:
10037: inline void msdos_int_21h_59h()
10038: {
1.1.1.23 root 10039: sda_t *sda = (sda_t *)(mem + SDA_TOP);
10040:
10041: REG16(AX) = sda->extended_error_code;
10042: REG8(BH) = sda->error_class;
10043: REG8(BL) = sda->suggested_action;
10044: REG8(CH) = sda->locus_of_last_error;
1.1 root 10045: }
10046:
10047: inline void msdos_int_21h_5ah()
10048: {
1.1.1.3 root 10049: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10050: int len = strlen(path);
10051: char tmp[MAX_PATH];
10052:
10053: if(GetTempFileName(path, "TMP", 0, tmp)) {
10054: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10055:
10056: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10057: REG16(AX) = fd;
10058: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10059: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10060:
10061: strcpy(path, tmp);
10062: int dx = REG16(DX) + len;
1.1.1.3 root 10063: int ds = SREG(DS);
1.1 root 10064: while(dx > 0xffff) {
10065: dx -= 0x10;
10066: ds++;
10067: }
10068: REG16(DX) = dx;
1.1.1.3 root 10069: SREG(DS) = ds;
10070: i386_load_segment_descriptor(DS);
1.1 root 10071: } else {
10072: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10073: m_CF = 1;
1.1 root 10074: }
10075: }
10076:
10077: inline void msdos_int_21h_5bh()
10078: {
1.1.1.3 root 10079: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10080:
1.1.1.24 root 10081: if(msdos_is_existing_file(path)) {
1.1 root 10082: // already exists
10083: REG16(AX) = 0x50;
1.1.1.3 root 10084: m_CF = 1;
1.1 root 10085: } else {
10086: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10087:
10088: if(fd != -1) {
10089: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10090: REG16(AX) = fd;
10091: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10092: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10093: } else {
10094: REG16(AX) = errno;
1.1.1.3 root 10095: m_CF = 1;
1.1 root 10096: }
10097: }
10098: }
10099:
10100: inline void msdos_int_21h_5ch()
10101: {
10102: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10103: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10104:
1.1.1.20 root 10105: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 10106: if(REG8(AL) == 0 || REG8(AL) == 1) {
1.1.1.35! root 10107: static const int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 10108: UINT32 pos = _tell(fd);
10109: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
10110: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 10111: REG16(AX) = errno;
1.1.1.3 root 10112: m_CF = 1;
1.1 root 10113: }
1.1.1.20 root 10114: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 10115:
1.1 root 10116: // some seconds may be passed in _locking()
1.1.1.35! root 10117: REQUEST_HARDWRE_UPDATE();
1.1 root 10118: } else {
10119: REG16(AX) = 0x01;
1.1.1.3 root 10120: m_CF = 1;
1.1 root 10121: }
10122: } else {
10123: REG16(AX) = 0x06;
1.1.1.3 root 10124: m_CF = 1;
1.1 root 10125: }
10126: }
10127:
1.1.1.22 root 10128: inline void msdos_int_21h_5dh()
10129: {
10130: switch(REG8(AL)) {
10131: case 0x06: // get address of dos swappable data area
1.1.1.23 root 10132: SREG(DS) = (SDA_TOP >> 4);
10133: i386_load_segment_descriptor(DS);
10134: REG16(SI) = offsetof(sda_t, crit_error_flag);
10135: REG16(CX) = 0x80;
10136: REG16(DX) = 0x1a;
10137: break;
10138: case 0x0b: // get dos swappable data areas
1.1.1.22 root 10139: REG16(AX) = 0x01;
10140: m_CF = 1;
10141: break;
10142: case 0x08: // set redirected printer mode
10143: case 0x09: // flush redirected printer output
10144: case 0x0a: // set extended error information
10145: break;
10146: default:
10147: 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));
10148: REG16(AX) = 0x01;
10149: m_CF = 1;
10150: break;
10151: }
10152: }
10153:
1.1.1.30 root 10154: inline void msdos_int_21h_5fh()
10155: {
10156: switch(REG8(AL)) {
10157: case 0x02:
10158: {
10159: DWORD drives = GetLogicalDrives();
10160: for(int i = 0, index = 0; i < 26; i++) {
10161: if(drives & (1 << i)) {
10162: char volume[] = "A:\\";
10163: volume[0] = 'A' + i;
10164: if(GetDriveType(volume) == DRIVE_REMOTE) {
10165: if(index == REG16(BX)) {
10166: DWORD dwSize = 128;
10167: volume[2] = '\0';
10168: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
10169: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
10170: REG8(BH) = 0x00; // valid
10171: REG8(BL) = 0x04; // disk drive
10172: REG16(CX) = 0x00;
10173: return;
10174: }
10175: index++;
10176: }
10177: }
10178: }
10179: }
10180: REG16(AX) = 0x12; // no more files
10181: m_CF = 1;
10182: break;
10183: default:
10184: 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));
10185: REG16(AX) = 0x01;
10186: m_CF = 1;
10187: break;
10188: }
10189: }
10190:
1.1 root 10191: inline void msdos_int_21h_60h(int lfn)
10192: {
1.1.1.14 root 10193: char full[MAX_PATH], *path;
10194:
1.1 root 10195: if(lfn) {
1.1.1.14 root 10196: char *name;
10197: *full = '\0';
1.1.1.3 root 10198: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 10199: switch(REG8(CL)) {
10200: case 1:
10201: GetShortPathName(full, full, MAX_PATH);
10202: my_strupr(full);
10203: break;
10204: case 2:
10205: GetLongPathName(full, full, MAX_PATH);
10206: break;
10207: }
10208: path = full;
10209: } else {
10210: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
10211: }
10212: if(*path != '\0') {
10213: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 10214: } else {
1.1.1.14 root 10215: REG16(AX) = (UINT16)GetLastError();
10216: m_CF = 1;
1.1 root 10217: }
10218: }
10219:
10220: inline void msdos_int_21h_61h()
10221: {
10222: REG8(AL) = 0;
10223: }
10224:
10225: inline void msdos_int_21h_62h()
10226: {
10227: REG16(BX) = current_psp;
10228: }
10229:
10230: inline void msdos_int_21h_63h()
10231: {
10232: switch(REG8(AL)) {
10233: case 0x00:
1.1.1.3 root 10234: SREG(DS) = (DBCS_TABLE >> 4);
10235: i386_load_segment_descriptor(DS);
1.1 root 10236: REG16(SI) = (DBCS_TABLE & 0x0f);
10237: REG8(AL) = 0x00;
10238: break;
1.1.1.22 root 10239: case 0x01: // set korean input mode
10240: case 0x02: // get korean input mode
10241: REG8(AL) = 0xff; // not supported
10242: break;
1.1 root 10243: default:
1.1.1.22 root 10244: 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 10245: REG16(AX) = 0x01;
1.1.1.3 root 10246: m_CF = 1;
1.1 root 10247: break;
10248: }
10249: }
10250:
1.1.1.25 root 10251: UINT16 get_extended_country_info(UINT8 func)
1.1 root 10252: {
1.1.1.25 root 10253: switch(func) {
1.1.1.17 root 10254: case 0x01:
10255: if(REG16(CX) >= 5) {
1.1.1.19 root 10256: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 10257: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
10258: REG16(CX) = sizeof(data);
10259: ZeroMemory(data, sizeof(data));
10260: data[0] = 0x01;
10261: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 10262: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 10263: *(UINT16 *)(data + 5) = active_code_page;
10264: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 10265: // REG16(AX) = active_code_page;
1.1.1.17 root 10266: } else {
1.1.1.25 root 10267: return(0x08); // insufficient memory
1.1.1.17 root 10268: }
10269: break;
10270: case 0x02:
10271: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
10272: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
10273: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 10274: // REG16(AX) = active_code_page;
1.1.1.17 root 10275: REG16(CX) = 0x05;
10276: break;
1.1.1.23 root 10277: case 0x03:
10278: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
10279: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
10280: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 10281: // REG16(AX) = active_code_page;
1.1.1.23 root 10282: REG16(CX) = 0x05;
10283: break;
1.1.1.17 root 10284: case 0x04:
10285: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
10286: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
10287: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 10288: // REG16(AX) = active_code_page;
1.1.1.17 root 10289: REG16(CX) = 0x05;
10290: break;
10291: case 0x05:
10292: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
10293: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
10294: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 10295: // REG16(AX) = active_code_page;
1.1.1.17 root 10296: REG16(CX) = 0x05;
10297: break;
10298: case 0x06:
10299: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
10300: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
10301: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 10302: // REG16(AX) = active_code_page;
1.1.1.17 root 10303: REG16(CX) = 0x05;
10304: break;
1.1 root 10305: case 0x07:
1.1.1.3 root 10306: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
10307: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
10308: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 10309: // REG16(AX) = active_code_page;
1.1 root 10310: REG16(CX) = 0x05;
10311: break;
1.1.1.25 root 10312: default:
10313: return(0x01); // function number invalid
10314: }
10315: return(0x00);
10316: }
10317:
10318: inline void msdos_int_21h_65h()
10319: {
10320: char tmp[0x10000];
10321:
10322: switch(REG8(AL)) {
10323: case 0x01:
10324: case 0x02:
10325: case 0x03:
10326: case 0x04:
10327: case 0x05:
10328: case 0x06:
10329: case 0x07:
10330: {
10331: UINT16 result = get_extended_country_info(REG8(AL));
10332: if(result) {
10333: REG16(AX) = result;
10334: m_CF = 1;
10335: } else {
10336: REG16(AX) = active_code_page; // FIXME: is this correct???
10337: }
10338: }
10339: break;
1.1 root 10340: case 0x20:
1.1.1.25 root 10341: case 0xa0:
1.1.1.19 root 10342: memset(tmp, 0, sizeof(tmp));
10343: tmp[0] = REG8(DL);
1.1 root 10344: my_strupr(tmp);
10345: REG8(DL) = tmp[0];
10346: break;
10347: case 0x21:
1.1.1.25 root 10348: case 0xa1:
1.1 root 10349: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 10350: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10351: my_strupr(tmp);
1.1.1.3 root 10352: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 10353: break;
10354: case 0x22:
1.1.1.25 root 10355: case 0xa2:
1.1.1.3 root 10356: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 10357: break;
1.1.1.25 root 10358: case 0x23:
10359: // FIXME: need to check multi-byte (kanji) charactre?
10360: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
10361: // 8278h/8299h: multi-byte (kanji) Y and y
10362: REG16(AX) = 0x00;
10363: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
10364: // 826dh/828eh: multi-byte (kanji) N and n
10365: REG16(AX) = 0x01;
10366: } else {
10367: REG16(AX) = 0x02;
10368: }
10369: break;
1.1 root 10370: default:
1.1.1.22 root 10371: 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 10372: REG16(AX) = 0x01;
1.1.1.3 root 10373: m_CF = 1;
1.1 root 10374: break;
10375: }
10376: }
10377:
10378: inline void msdos_int_21h_66h()
10379: {
10380: switch(REG8(AL)) {
10381: case 0x01:
10382: REG16(BX) = active_code_page;
10383: REG16(DX) = system_code_page;
10384: break;
10385: case 0x02:
10386: if(active_code_page == REG16(BX)) {
10387: REG16(AX) = 0xeb41;
10388: } else if(_setmbcp(REG16(BX)) == 0) {
10389: active_code_page = REG16(BX);
1.1.1.17 root 10390: msdos_nls_tables_update();
1.1 root 10391: REG16(AX) = 0xeb41;
1.1.1.32 root 10392: SetConsoleCP(active_code_page);
10393: SetConsoleOutputCP(active_code_page);
1.1 root 10394: } else {
10395: REG16(AX) = 0x25;
1.1.1.3 root 10396: m_CF = 1;
1.1 root 10397: }
10398: break;
10399: default:
1.1.1.22 root 10400: 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 10401: REG16(AX) = 0x01;
1.1.1.3 root 10402: m_CF = 1;
1.1 root 10403: break;
10404: }
10405: }
10406:
10407: inline void msdos_int_21h_67h()
10408: {
10409: process_t *process = msdos_process_info_get(current_psp);
10410:
10411: if(REG16(BX) <= MAX_FILES) {
10412: process->max_files = max(REG16(BX), 20);
10413: } else {
10414: REG16(AX) = 0x08;
1.1.1.3 root 10415: m_CF = 1;
1.1 root 10416: }
10417: }
10418:
10419: inline void msdos_int_21h_68h()
10420: {
10421: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10422: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10423:
1.1.1.20 root 10424: if(fd < process->max_files && file_handler[fd].valid) {
10425: // fflush(_fdopen(fd, ""));
1.1 root 10426: } else {
10427: REG16(AX) = 0x06;
1.1.1.3 root 10428: m_CF = 1;
1.1 root 10429: }
10430: }
10431:
10432: inline void msdos_int_21h_69h()
10433: {
1.1.1.3 root 10434: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10435: char path[] = "A:\\";
10436: char volume_label[MAX_PATH];
10437: DWORD serial_number = 0;
10438: char file_system[MAX_PATH];
10439:
10440: if(REG8(BL) == 0) {
10441: path[0] = 'A' + _getdrive() - 1;
10442: } else {
10443: path[0] = 'A' + REG8(BL) - 1;
10444: }
10445:
10446: switch(REG8(AL)) {
10447: case 0x00:
10448: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
10449: info->info_level = 0;
10450: info->serial_number = serial_number;
10451: memset(info->volume_label, 0x20, 11);
10452: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
10453: memset(info->file_system, 0x20, 8);
10454: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
10455: } else {
10456: REG16(AX) = errno;
1.1.1.3 root 10457: m_CF = 1;
1.1 root 10458: }
10459: break;
10460: case 0x01:
10461: REG16(AX) = 0x03;
1.1.1.3 root 10462: m_CF = 1;
1.1 root 10463: }
10464: }
10465:
10466: inline void msdos_int_21h_6ah()
10467: {
10468: REG8(AH) = 0x68;
10469: msdos_int_21h_68h();
10470: }
10471:
10472: inline void msdos_int_21h_6bh()
10473: {
10474: REG8(AL) = 0;
10475: }
10476:
10477: inline void msdos_int_21h_6ch(int lfn)
10478: {
1.1.1.3 root 10479: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 10480: int mode = REG8(BL) & 0x03;
10481:
10482: if(mode < 0x03) {
1.1.1.29 root 10483: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 10484: // file exists
10485: if(REG8(DL) & 1) {
1.1.1.29 root 10486: int fd = -1, c;
1.1.1.11 root 10487: UINT16 info;
1.1 root 10488:
1.1.1.11 root 10489: if(msdos_is_con_path(path)) {
1.1.1.13 root 10490: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 10491: info = 0x80d3;
1.1.1.29 root 10492: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
10493: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
10494: fd = msdos_open("NUL", file_mode[mode].mode);
10495: }
1.1.1.14 root 10496: info = 0x80d3;
1.1.1.29 root 10497: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10498: fd = msdos_open("NUL", file_mode[mode].mode);
10499: info = 0x80d3;
1.1.1.11 root 10500: } else {
1.1.1.13 root 10501: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 10502: info = msdos_drive_number(path);
10503: }
1.1 root 10504: if(fd != -1) {
10505: REG16(AX) = fd;
10506: REG16(CX) = 1;
1.1.1.11 root 10507: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 10508: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10509: } else {
10510: REG16(AX) = errno;
1.1.1.3 root 10511: m_CF = 1;
1.1 root 10512: }
10513: } else if(REG8(DL) & 2) {
10514: int attr = GetFileAttributes(path);
1.1.1.29 root 10515: int fd = -1, c;
1.1.1.11 root 10516: UINT16 info;
1.1 root 10517:
1.1.1.11 root 10518: if(msdos_is_con_path(path)) {
1.1.1.13 root 10519: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 10520: info = 0x80d3;
1.1.1.29 root 10521: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
10522: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
10523: fd = msdos_open("NUL", file_mode[mode].mode);
10524: }
1.1.1.14 root 10525: info = 0x80d3;
1.1.1.29 root 10526: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10527: fd = msdos_open("NUL", file_mode[mode].mode);
10528: info = 0x80d3;
1.1 root 10529: } else {
10530: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 10531: info = msdos_drive_number(path);
1.1 root 10532: }
10533: if(fd != -1) {
10534: if(attr == -1) {
10535: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
10536: }
10537: SetFileAttributes(path, attr);
10538: REG16(AX) = fd;
10539: REG16(CX) = 3;
1.1.1.11 root 10540: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 10541: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10542: } else {
10543: REG16(AX) = errno;
1.1.1.3 root 10544: m_CF = 1;
1.1 root 10545: }
10546: } else {
10547: REG16(AX) = 0x50;
1.1.1.3 root 10548: m_CF = 1;
1.1 root 10549: }
10550: } else {
10551: // file not exists
10552: if(REG8(DL) & 0x10) {
10553: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10554:
10555: if(fd != -1) {
10556: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10557: REG16(AX) = fd;
10558: REG16(CX) = 2;
10559: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10560: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10561: } else {
10562: REG16(AX) = errno;
1.1.1.3 root 10563: m_CF = 1;
1.1 root 10564: }
10565: } else {
10566: REG16(AX) = 0x02;
1.1.1.3 root 10567: m_CF = 1;
1.1 root 10568: }
10569: }
10570: } else {
10571: REG16(AX) = 0x0c;
1.1.1.3 root 10572: m_CF = 1;
1.1 root 10573: }
10574: }
10575:
10576: inline void msdos_int_21h_710dh()
10577: {
10578: // reset drive
10579: }
10580:
1.1.1.17 root 10581: inline void msdos_int_21h_7141h(int lfn)
10582: {
10583: if(REG16(SI) == 0) {
10584: msdos_int_21h_41h(lfn);
10585: return;
10586: }
10587: if(REG16(SI) != 1) {
10588: REG16(AX) = 5;
10589: m_CF = 1;
10590: }
10591: /* wild card and matching attributes... */
10592: char tmp[MAX_PATH * 2];
10593: // copy search pathname (and quick check overrun)
10594: ZeroMemory(tmp, sizeof(tmp));
10595: tmp[MAX_PATH - 1] = '\0';
10596: tmp[MAX_PATH] = 1;
10597: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
10598:
10599: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
10600: REG16(AX) = 1;
10601: m_CF = 1;
10602: return;
10603: }
10604: for(char *s = tmp; *s; ++s) {
10605: if(*s == '/') {
10606: *s = '\\';
10607: }
10608: }
10609: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
10610: if(tmp_name) {
10611: ++tmp_name;
10612: } else {
10613: tmp_name = strchr(tmp, ':');
10614: tmp_name = tmp_name ? tmp_name + 1 : tmp;
10615: }
10616:
10617: WIN32_FIND_DATAA fd;
10618: HANDLE fh = FindFirstFileA(tmp, &fd);
10619: if(fh == INVALID_HANDLE_VALUE) {
10620: REG16(AX) = 2;
10621: m_CF = 1;
10622: return;
10623: }
10624: do {
10625: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
10626: strcpy(tmp_name, fd.cFileName);
10627: if(remove(msdos_trimmed_path(tmp, lfn))) {
10628: REG16(AX) = 5;
10629: m_CF = 1;
10630: break;
10631: }
10632: }
10633: } while(FindNextFileA(fh, &fd));
10634: if(!m_CF) {
10635: if(GetLastError() != ERROR_NO_MORE_FILES) {
10636: m_CF = 1;
10637: REG16(AX) = 2;
10638: }
10639: }
10640: FindClose(fh);
10641: }
10642:
1.1 root 10643: inline void msdos_int_21h_714eh()
10644: {
10645: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 10646: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
10647: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10648: WIN32_FIND_DATA fd;
10649:
1.1.1.13 root 10650: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
10651: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10652: FindClose(dtainfo->find_handle);
10653: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10654: }
10655: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 10656: dtainfo->allowable_mask = REG8(CL);
10657: dtainfo->required_mask = REG8(CH);
10658: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 10659:
1.1.1.14 root 10660: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
10661: dtainfo->allowable_mask &= ~8;
1.1 root 10662: }
1.1.1.14 root 10663: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
10664: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 10665: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10666: FindClose(dtainfo->find_handle);
10667: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10668: break;
10669: }
10670: }
10671: }
1.1.1.13 root 10672: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10673: find->attrib = fd.dwFileAttributes;
10674: msdos_find_file_conv_local_time(&fd);
10675: if(REG16(SI) == 0) {
10676: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
10677: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
10678: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
10679: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
10680: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
10681: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
10682: } else {
10683: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
10684: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
10685: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
10686: }
10687: find->size_hi = fd.nFileSizeHigh;
10688: find->size_lo = fd.nFileSizeLow;
10689: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 10690: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 10691: REG16(AX) = dtainfo - dtalist + 1;
10692: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10693: // volume label
10694: find->attrib = 8;
10695: find->size_hi = find->size_lo = 0;
10696: strcpy(find->full_name, process->volume_label);
10697: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10698: dtainfo->allowable_mask &= ~8;
10699: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 10700: } else {
10701: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 10702: m_CF = 1;
1.1 root 10703: }
10704: }
10705:
10706: inline void msdos_int_21h_714fh()
10707: {
10708: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 10709: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 10710: WIN32_FIND_DATA fd;
10711:
1.1.1.14 root 10712: if(REG16(BX) - 1u >= MAX_DTAINFO) {
10713: REG16(AX) = 6;
1.1.1.13 root 10714: m_CF = 1;
10715: return;
10716: }
1.1.1.14 root 10717: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 10718: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10719: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 10720: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 10721: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10722: FindClose(dtainfo->find_handle);
10723: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10724: break;
10725: }
10726: }
10727: } else {
1.1.1.13 root 10728: FindClose(dtainfo->find_handle);
10729: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10730: }
10731: }
1.1.1.13 root 10732: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10733: find->attrib = fd.dwFileAttributes;
10734: msdos_find_file_conv_local_time(&fd);
10735: if(REG16(SI) == 0) {
10736: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
10737: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
10738: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
10739: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
10740: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
10741: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
10742: } else {
10743: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
10744: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
10745: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
10746: }
10747: find->size_hi = fd.nFileSizeHigh;
10748: find->size_lo = fd.nFileSizeLow;
10749: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 10750: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 10751: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10752: // volume label
10753: find->attrib = 8;
10754: find->size_hi = find->size_lo = 0;
10755: strcpy(find->full_name, process->volume_label);
10756: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10757: dtainfo->allowable_mask &= ~8;
1.1 root 10758: } else {
10759: REG16(AX) = 0x12;
1.1.1.3 root 10760: m_CF = 1;
1.1 root 10761: }
10762: }
10763:
10764: inline void msdos_int_21h_71a0h()
10765: {
10766: DWORD max_component_len, file_sys_flag;
10767:
1.1.1.14 root 10768: 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))) {
10769: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
10770: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 10771: REG16(CX) = (UINT16)max_component_len; // 255
10772: REG16(DX) = (UINT16)max_component_len + 5; // 260
10773: } else {
10774: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10775: m_CF = 1;
1.1 root 10776: }
10777: }
10778:
10779: inline void msdos_int_21h_71a1h()
10780: {
1.1.1.14 root 10781: if(REG16(BX) - 1u >= MAX_DTAINFO) {
10782: REG16(AX) = 6;
1.1.1.13 root 10783: m_CF = 1;
10784: return;
10785: }
1.1.1.14 root 10786: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 10787: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10788: FindClose(dtainfo->find_handle);
10789: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10790: }
10791: }
10792:
10793: inline void msdos_int_21h_71a6h()
10794: {
10795: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10796: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
10797:
1.1.1.3 root 10798: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10799: struct _stat64 status;
10800: DWORD serial_number = 0;
10801:
1.1.1.20 root 10802: if(fd < process->max_files && file_handler[fd].valid) {
10803: if(_fstat64(fd, &status) == 0) {
10804: if(file_handler[fd].path[1] == ':') {
1.1 root 10805: // NOTE: we need to consider the network file path "\\host\share\"
10806: char volume[] = "A:\\";
1.1.1.20 root 10807: volume[0] = file_handler[fd].path[1];
1.1 root 10808: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
10809: }
1.1.1.20 root 10810: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 10811: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
10812: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
10813: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
10814: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
10815: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
10816: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
10817: *(UINT32 *)(buffer + 0x1c) = serial_number;
10818: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
10819: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
10820: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 10821: // this is dummy id and it will be changed when it is reopened...
1.1 root 10822: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 10823: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 10824: } else {
10825: REG16(AX) = errno;
1.1.1.3 root 10826: m_CF = 1;
1.1 root 10827: }
10828: } else {
10829: REG16(AX) = 0x06;
1.1.1.3 root 10830: m_CF = 1;
1.1 root 10831: }
10832: }
10833:
10834: inline void msdos_int_21h_71a7h()
10835: {
10836: switch(REG8(BL)) {
10837: case 0x00:
1.1.1.3 root 10838: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 10839: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10840: m_CF = 1;
1.1 root 10841: }
10842: break;
10843: case 0x01:
10844: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 10845: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 10846: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10847: m_CF = 1;
1.1 root 10848: }
10849: break;
10850: default:
1.1.1.22 root 10851: 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 10852: REG16(AX) = 0x01;
1.1.1.3 root 10853: m_CF = 1;
1.1 root 10854: break;
10855: }
10856: }
10857:
10858: inline void msdos_int_21h_71a8h()
10859: {
10860: if(REG8(DH) == 0) {
10861: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 10862: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 10863: memset(fcb, 0x20, sizeof(fcb));
10864: int len = strlen(tmp);
1.1.1.21 root 10865: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 10866: if(tmp[i] == '.') {
10867: pos = 8;
10868: } else {
10869: if(msdos_lead_byte_check(tmp[i])) {
10870: fcb[pos++] = tmp[i++];
10871: }
10872: fcb[pos++] = tmp[i];
10873: }
10874: }
1.1.1.3 root 10875: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 10876: } else {
1.1.1.3 root 10877: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 10878: }
10879: }
10880:
1.1.1.22 root 10881: inline void msdos_int_21h_71aah()
10882: {
10883: char drv[] = "A:", path[MAX_PATH];
10884: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
10885:
10886: if(REG8(BL) == 0) {
10887: drv[0] = 'A' + _getdrive() - 1;
10888: } else {
10889: drv[0] = 'A' + REG8(BL) - 1;
10890: }
10891: switch(REG8(BH)) {
10892: case 0x00:
10893: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
10894: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10895: if(GetLogicalDrives() & bits) {
10896: REG16(AX) = 0x0f; // invalid drive
10897: } else {
10898: REG16(AX) = 0x03; // path not found
10899: }
10900: m_CF = 1;
10901: }
10902: break;
10903: case 0x01:
10904: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
10905: REG16(AX) = 0x0f; // invalid drive
10906: m_CF = 1;
10907: }
10908: break;
10909: case 0x02:
10910: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
10911: REG16(AX) = 0x0f; // invalid drive
10912: m_CF = 1;
10913: } else if(strncmp(path, "\\??\\", 4) != 0) {
10914: REG16(AX) = 0x0f; // invalid drive
10915: m_CF = 1;
10916: } else {
10917: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
10918: }
10919: break;
10920: default:
10921: 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));
10922: REG16(AX) = 0x01;
10923: m_CF = 1;
10924: break;
10925: }
10926: }
10927:
1.1.1.14 root 10928: inline void msdos_int_21h_7300h()
10929: {
10930: if(REG8(AL) == 0) {
10931: REG8(AL) = REG8(CL);
10932: REG8(AH) = 0;
10933: } else {
10934: REG16(AX) = 0x01;
10935: m_CF = 1;
10936: }
10937: }
10938:
10939: inline void msdos_int_21h_7302h()
10940: {
10941: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
10942: UINT16 seg, ofs;
10943:
10944: if(REG16(CX) < 0x3f) {
10945: REG8(AL) = 0x18;
10946: m_CF = 1;
10947: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
10948: REG8(AL) = 0xff;
10949: m_CF = 1;
10950: } else {
10951: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
10952: }
10953: }
10954:
1.1 root 10955: inline void msdos_int_21h_7303h()
10956: {
1.1.1.3 root 10957: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
10958: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 10959: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
10960:
10961: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
10962: info->size_of_structure = sizeof(ext_space_info_t);
10963: info->structure_version = 0;
10964: info->sectors_per_cluster = sectors_per_cluster;
10965: info->bytes_per_sector = bytes_per_sector;
10966: info->available_clusters_on_drive = free_clusters;
10967: info->total_clusters_on_drive = total_clusters;
10968: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
10969: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
10970: info->available_allocation_units = free_clusters; // ???
10971: info->total_allocation_units = total_clusters; // ???
10972: } else {
10973: REG16(AX) = errno;
1.1.1.3 root 10974: m_CF = 1;
1.1 root 10975: }
10976: }
10977:
1.1.1.30 root 10978: inline void msdos_int_21h_dbh()
10979: {
10980: // Novell NetWare - Workstation - Get Number of Local Drives
10981: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
10982: REG8(AL) = dos_info->last_drive;
10983: }
10984:
10985: inline void msdos_int_21h_dch()
10986: {
10987: // Novell NetWare - Connection Services - Get Connection Number
10988: REG8(AL) = 0x00;
10989: }
10990:
1.1.1.32 root 10991: inline void msdos_int_24h()
10992: {
10993: const char *message = NULL;
10994: int key = 0;
10995:
10996: for(int i = 0; i < array_length(critical_error_table); i++) {
10997: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
10998: if(active_code_page == 932) {
10999: message = critical_error_table[i].message_japanese;
11000: }
11001: if(message == NULL) {
11002: message = critical_error_table[i].message_english;
11003: }
11004: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
11005: strcpy((char *)(mem + WORK_TOP + 1), message);
11006:
11007: SREG(ES) = WORK_TOP >> 4;
11008: i386_load_segment_descriptor(ES);
11009: REG16(DI) = 0x0000;
11010: break;
11011: }
11012: }
11013: fprintf(stderr, "\n%s", message);
11014: if(!(REG8(AH) & 0x80)) {
11015: if(REG8(AH) & 0x01) {
11016: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
11017: } else {
11018: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
11019: }
11020: }
11021: fprintf(stderr, "\n");
11022:
1.1.1.33 root 11023: {
1.1.1.32 root 11024: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
1.1.1.33 root 11025: }
1.1.1.32 root 11026: if(REG8(AH) & 0x10) {
11027: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
11028: }
11029: if(REG8(AH) & 0x20) {
11030: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
11031: }
11032: if(REG8(AH) & 0x08) {
11033: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
11034: }
11035: fprintf(stderr, "? ");
11036:
11037: while(1) {
11038: while(!_kbhit()) {
11039: Sleep(10);
11040: }
11041: key = _getch();
11042:
11043: if(key == 'I' || key == 'i') {
11044: if(REG8(AH) & 0x20) {
11045: REG8(AL) = 0;
11046: break;
11047: }
11048: } else if(key == 'R' || key == 'r') {
11049: if(REG8(AH) & 0x10) {
11050: REG8(AL) = 1;
11051: break;
11052: }
11053: } else if(key == 'A' || key == 'a') {
11054: REG8(AL) = 2;
11055: break;
11056: } else if(key == 'F' || key == 'f') {
11057: if(REG8(AH) & 0x08) {
11058: REG8(AL) = 3;
11059: break;
11060: }
11061: }
11062: }
11063: fprintf(stderr, "%c\n", key);
11064: }
11065:
1.1 root 11066: inline void msdos_int_25h()
11067: {
11068: UINT16 seg, ofs;
11069: DWORD dwSize;
11070:
1.1.1.3 root 11071: #if defined(HAS_I386)
11072: I386OP(pushf)();
11073: #else
11074: PREFIX86(_pushf());
11075: #endif
1.1 root 11076:
11077: if(!(REG8(AL) < 26)) {
11078: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 11079: m_CF = 1;
1.1 root 11080: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
11081: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11082: m_CF = 1;
1.1 root 11083: } else {
11084: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
11085: char dev[64];
11086: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
11087:
11088: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
11089: if(hFile == INVALID_HANDLE_VALUE) {
11090: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11091: m_CF = 1;
1.1 root 11092: } else {
1.1.1.19 root 11093: UINT32 top_sector = REG16(DX);
11094: UINT16 sector_num = REG16(CX);
11095: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
11096:
11097: if(sector_num == 0xffff) {
11098: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
11099: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
11100: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
11101: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
11102: buffer_addr = (seg << 4) + ofs;
11103: }
11104: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
11105: // REG8(AL) = 0x02; // drive not ready
11106: // m_CF = 1;
11107: // } else
11108: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 11109: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 11110: m_CF = 1;
1.1.1.19 root 11111: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 11112: REG8(AL) = 0x0b; // read error
1.1.1.3 root 11113: m_CF = 1;
1.1 root 11114: }
11115: CloseHandle(hFile);
11116: }
11117: }
11118: }
11119:
11120: inline void msdos_int_26h()
11121: {
11122: // this operation may cause serious damage for drives, so always returns error...
11123: UINT16 seg, ofs;
11124: DWORD dwSize;
11125:
1.1.1.3 root 11126: #if defined(HAS_I386)
11127: I386OP(pushf)();
11128: #else
11129: PREFIX86(_pushf());
11130: #endif
1.1 root 11131:
11132: if(!(REG8(AL) < 26)) {
11133: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 11134: m_CF = 1;
1.1 root 11135: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
11136: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11137: m_CF = 1;
1.1 root 11138: } else {
11139: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
11140: char dev[64];
11141: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
11142:
11143: if(dpb->media_type == 0xf8) {
11144: // this drive is not a floppy
1.1.1.6 root 11145: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
11146: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
11147: // }
1.1 root 11148: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11149: m_CF = 1;
1.1 root 11150: } else {
11151: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
11152: if(hFile == INVALID_HANDLE_VALUE) {
11153: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11154: m_CF = 1;
1.1 root 11155: } else {
1.1.1.19 root 11156: UINT32 top_sector = REG16(DX);
11157: UINT16 sector_num = REG16(CX);
11158: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
11159:
11160: if(sector_num == 0xffff) {
11161: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
11162: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
11163: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
11164: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
11165: buffer_addr = (seg << 4) + ofs;
11166: }
1.1 root 11167: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
11168: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11169: m_CF = 1;
1.1.1.19 root 11170: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 11171: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 11172: m_CF = 1;
1.1.1.19 root 11173: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 11174: REG8(AL) = 0x0a; // write error
1.1.1.3 root 11175: m_CF = 1;
1.1 root 11176: }
11177: CloseHandle(hFile);
11178: }
11179: }
11180: }
11181: }
11182:
11183: inline void msdos_int_27h()
11184: {
1.1.1.29 root 11185: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
11186: try {
11187: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
11188: } catch(...) {
11189: // recover the broken mcb
11190: int mcb_seg = SREG(CS) - 1;
11191: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 11192:
1.1.1.29 root 11193: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 11194: mcb->mz = 'M';
11195: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
11196:
1.1.1.29 root 11197: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.33 root 11198: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4));
1.1.1.29 root 11199: } else {
1.1.1.33 root 11200: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0);
1.1.1.29 root 11201: }
11202: } else {
11203: mcb->mz = 'Z';
1.1.1.30 root 11204: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 11205: }
11206: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
11207: }
1.1.1.3 root 11208: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 11209: }
11210:
11211: inline void msdos_int_29h()
11212: {
1.1.1.14 root 11213: #if 1
11214: // need to check escape sequences
1.1 root 11215: msdos_putch(REG8(AL));
1.1.1.14 root 11216: #else
11217: DWORD num;
11218: vram_flush();
1.1.1.23 root 11219: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 11220: cursor_moved = true;
11221: #endif
1.1 root 11222: }
11223:
11224: inline void msdos_int_2eh()
11225: {
11226: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
11227: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 11228: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 11229: char *token = my_strtok(tmp, " ");
11230: strcpy(command, token);
11231: strcpy(opt, token + strlen(token) + 1);
11232:
11233: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
11234: param->env_seg = 0;
11235: param->cmd_line.w.l = 44;
11236: param->cmd_line.w.h = (WORK_TOP >> 4);
11237: param->fcb1.w.l = 24;
11238: param->fcb1.w.h = (WORK_TOP >> 4);
11239: param->fcb2.w.l = 24;
11240: param->fcb2.w.h = (WORK_TOP >> 4);
11241:
11242: memset(mem + WORK_TOP + 24, 0x20, 20);
11243:
11244: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
11245: cmd_line->len = strlen(opt);
11246: strcpy(cmd_line->cmd, opt);
11247: cmd_line->cmd[cmd_line->len] = 0x0d;
11248:
1.1.1.28 root 11249: try {
11250: if(msdos_process_exec(command, param, 0)) {
11251: REG16(AX) = 0xffff; // error before processing command
11252: } else {
11253: // set flag to set retval to ax when the started process is terminated
11254: process_t *process = msdos_process_info_get(current_psp);
11255: process->called_by_int2eh = true;
11256: }
11257: } catch(...) {
11258: REG16(AX) = 0xffff; // error before processing command
11259: }
1.1 root 11260: }
11261:
1.1.1.29 root 11262: inline void msdos_int_2fh_05h()
11263: {
11264: switch(REG8(AL)) {
11265: case 0x00:
1.1.1.32 root 11266: REG8(AL) = 0xff;
11267: break;
11268: case 0x01:
11269: case 0x02:
11270: for(int i = 0; i < array_length(standard_error_table); i++) {
11271: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
11272: const char *message = NULL;
11273: if(active_code_page == 932) {
11274: message = standard_error_table[i].message_japanese;
11275: }
11276: if(message == NULL) {
11277: message = standard_error_table[i].message_english;
11278: }
11279: strcpy((char *)(mem + WORK_TOP), message);
11280:
11281: SREG(ES) = WORK_TOP >> 4;
11282: i386_load_segment_descriptor(ES);
11283: REG16(DI) = 0x0000;
11284: REG8(AL) = 0x01;
11285: break;
11286: }
11287: }
1.1.1.29 root 11288: break;
11289: default:
11290: 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));
11291: m_CF = 1;
11292: }
11293: }
11294:
1.1.1.22 root 11295: inline void msdos_int_2fh_11h()
11296: {
11297: switch(REG8(AL)) {
11298: case 0x00:
1.1.1.29 root 11299: if(i386_read_stack() == 0xdada) {
11300: // MSCDEX is not installed
11301: // REG8(AL) = 0x00;
11302: } else {
11303: // Network Redirector is not installed
11304: // REG8(AL) = 0x00;
11305: }
1.1.1.22 root 11306: break;
11307: default:
11308: 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 11309: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 11310: m_CF = 1;
11311: break;
11312: }
11313: }
11314:
1.1.1.21 root 11315: inline void msdos_int_2fh_12h()
11316: {
11317: switch(REG8(AL)) {
1.1.1.22 root 11318: case 0x00:
1.1.1.29 root 11319: // DOS 3.0+ internal functions are installed
1.1.1.22 root 11320: REG8(AL) = 0xff;
11321: break;
1.1.1.29 root 11322: // case 0x01: // DOS 3.0+ internal - Close Current File
11323: case 0x02:
11324: {
11325: UINT16 stack = i386_read_stack();
11326: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
11327: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
11328: i386_load_segment_descriptor(ES);
11329: }
11330: break;
1.1.1.30 root 11331: case 0x03:
11332: SREG(DS) = (DEVICE_TOP >> 4);
11333: i386_load_segment_descriptor(DS);
11334: break;
1.1.1.29 root 11335: case 0x04:
11336: {
11337: UINT16 stack = i386_read_stack();
11338: REG8(AL) = (stack == '/') ? '\\' : stack;
11339: #if defined(HAS_I386)
11340: m_ZF = (REG8(AL) == '\\');
11341: #else
11342: m_ZeroVal = (REG8(AL) != '\\');
11343: #endif
11344: }
11345: break;
11346: case 0x05:
11347: msdos_putch(i386_read_stack());
11348: break;
11349: // case 0x06: // DOS 3.0+ internal - Invole Critical Error
11350: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
11351: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
11352: // case 0x09: // DOS 3.0+ internal - Flush and FREE Disk Buffer
11353: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
11354: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
11355: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
11356: case 0x0d:
11357: {
11358: SYSTEMTIME time;
11359: FILETIME file_time;
11360: WORD dos_date, dos_time;
11361: GetLocalTime(&time);
11362: SystemTimeToFileTime(&time, &file_time);
11363: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
11364: REG16(AX) = dos_date;
11365: REG16(DX) = dos_time;
11366: }
11367: break;
11368: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
11369: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
11370: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
11371: case 0x11:
11372: {
11373: char path[MAX_PATH], *p;
11374: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
11375: my_strupr(path);
11376: while((p = my_strchr(path, '/')) != NULL) {
11377: *p = '\\';
11378: }
11379: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
11380: }
11381: break;
11382: case 0x12:
11383: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
11384: break;
11385: case 0x13:
11386: {
11387: char tmp[2] = {0};
11388: tmp[0] = i386_read_stack();
11389: my_strupr(tmp);
11390: REG8(AL) = tmp[0];
11391: }
11392: break;
11393: case 0x14:
11394: #if defined(HAS_I386)
11395: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
11396: #else
11397: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
11398: #endif
11399: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
11400: break;
11401: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 11402: case 0x16:
11403: if(REG16(BX) < 20) {
11404: SREG(ES) = SFT_TOP >> 4;
11405: i386_load_segment_descriptor(ES);
11406: REG16(DI) = 6 + 0x3b * REG16(BX);
11407:
11408: // update system file table
11409: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
11410: if(file_handler[REG16(BX)].valid) {
11411: int count = 0;
11412: for(int i = 0; i < 20; i++) {
11413: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
11414: count++;
11415: }
11416: }
11417: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
11418: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
11419: _lseek(REG16(BX), 0, SEEK_END);
11420: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
11421: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
11422: } else {
11423: memset(sft, 0, 0x3b);
11424: }
11425: } else {
11426: REG16(AX) = 0x06;
11427: m_CF = 1;
11428: }
11429: break;
1.1.1.29 root 11430: // case 0x17: // DOS 3.0+ internal - Get Current Directory Structure for Drive
11431: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
11432: // case 0x19: // DOS 3.0+ internal - Set Drive???
11433: case 0x1a:
11434: {
11435: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
11436: if(path[1] == ':') {
11437: if(path[0] >= 'a' && path[0] <= 'z') {
11438: REG8(AL) = path[0] - 'a' + 1;
11439: } else if(path[0] >= 'A' && path[0] <= 'Z') {
11440: REG8(AL) = path[0] - 'A' + 1;
11441: } else {
11442: REG8(AL) = 0xff; // invalid
11443: }
11444: strcpy(full, path);
11445: strcpy(path, full + 2);
11446: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
11447: if(full[0] >= 'a' && full[0] <= 'z') {
11448: REG8(AL) = full[0] - 'a' + 1;
11449: } else if(full[0] >= 'A' && full[0] <= 'Z') {
11450: REG8(AL) = full[0] - 'A' + 1;
11451: } else {
11452: REG8(AL) = 0xff; // invalid
11453: }
11454: } else {
11455: REG8(AL) = 0x00; // default
11456: }
11457: }
11458: break;
11459: case 0x1b:
11460: {
11461: int year = REG16(CX) + 1980;
11462: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
11463: }
11464: break;
11465: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
11466: // case 0x1d: // DOS 3.0+ internal - Sum Memory
11467: case 0x1e:
11468: {
11469: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
11470: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
11471: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
11472: #if defined(HAS_I386)
11473: m_ZF = (strcmp(full_1st, full_2nd) == 0);
11474: #else
11475: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
11476: #endif
11477: } else {
11478: #if defined(HAS_I386)
11479: m_ZF = (strcmp(path_1st, path_2nd) == 0);
11480: #else
11481: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
11482: #endif
11483: }
11484: }
11485: break;
11486: // case 0x1f: // DOS 3.0+ internal - Build Current Directory Structure
1.1.1.21 root 11487: case 0x20:
11488: {
11489: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11490:
11491: if(fd < 20) {
11492: SREG(ES) = current_psp;
11493: i386_load_segment_descriptor(ES);
11494: REG16(DI) = offsetof(psp_t, file_table) + fd;
11495: } else {
11496: REG16(AX) = 0x06;
11497: m_CF = 1;
11498: }
11499: }
11500: break;
1.1.1.29 root 11501: case 0x21:
11502: msdos_int_21h_60h(0);
11503: break;
11504: // case 0x22: // DOS 3.0+ internal - Set Extended Error Info
11505: // case 0x23: // DOS 3.0+ internal - Check If Character Device
11506: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
11507: case 0x25:
11508: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
11509: break;
11510: case 0x26:
11511: REG8(AL) = REG8(CL);
11512: msdos_int_21h_3dh();
11513: break;
11514: case 0x27:
11515: msdos_int_21h_3eh();
11516: break;
11517: case 0x28:
11518: REG16(AX) = REG16(BP);
11519: msdos_int_21h_42h();
11520: break;
11521: case 0x29:
11522: msdos_int_21h_3fh();
11523: break;
11524: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
11525: case 0x2b:
11526: REG16(AX) = REG16(BP);
11527: msdos_int_21h_44h();
11528: break;
11529: case 0x2c:
11530: REG16(BX) = DEVICE_TOP >> 4;
11531: REG16(AX) = 22;
11532: break;
11533: case 0x2d:
11534: {
11535: sda_t *sda = (sda_t *)(mem + SDA_TOP);
11536: REG16(AX) = sda->extended_error_code;
11537: }
11538: break;
11539: case 0x2e:
11540: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32 root 11541: SREG(ES) = 0x0001;
11542: i386_load_segment_descriptor(ES);
11543: REG16(DI) = 0x00;
11544: } else if(REG8(DL) == 0x08) {
11545: // dummy parameter error message read routine is at fffd:0010
11546: SREG(ES) = 0xfffd;
1.1.1.22 root 11547: i386_load_segment_descriptor(ES);
1.1.1.32 root 11548: REG16(DI) = 0x0010;
1.1.1.22 root 11549: }
11550: break;
1.1.1.29 root 11551: case 0x2f:
11552: if(REG16(DX) != 0) {
1.1.1.30 root 11553: dos_major_version = REG8(DL);
11554: dos_minor_version = REG8(DH);
1.1.1.29 root 11555: } else {
11556: REG8(DL) = 7;
11557: REG8(DH) = 10;
11558: }
11559: break;
11560: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
11561: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 11562: default:
11563: 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));
11564: REG16(AX) = 0x01;
11565: m_CF = 1;
11566: break;
11567: }
11568: }
11569:
1.1.1.30 root 11570: inline void msdos_int_2fh_13h()
11571: {
11572: static UINT16 prevDS = 0, prevDX = 0;
11573: static UINT16 prevES = 0, prevBX = 0;
11574: UINT16 tmp;
11575:
11576: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
11577: i386_load_segment_descriptor(DS);
11578: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
11579:
11580: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
11581: i386_load_segment_descriptor(ES);
11582: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
11583: }
11584:
1.1.1.22 root 11585: inline void msdos_int_2fh_14h()
11586: {
11587: switch(REG8(AL)) {
11588: case 0x00:
1.1.1.29 root 11589: // NLSFUNC.COM is installed
11590: REG8(AL) = 0xff;
1.1.1.25 root 11591: break;
11592: case 0x01:
11593: case 0x03:
11594: REG8(AL) = 0x00;
11595: active_code_page = REG16(BX);
11596: msdos_nls_tables_update();
11597: break;
11598: case 0x02:
11599: REG8(AL) = get_extended_country_info(REG16(BP));
11600: break;
11601: case 0x04:
11602: REG8(AL) = 0x00;
11603: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 11604: break;
11605: default:
11606: 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));
11607: REG16(AX) = 0x01;
11608: m_CF = 1;
11609: break;
11610: }
11611: }
11612:
11613: inline void msdos_int_2fh_15h()
11614: {
11615: switch(REG8(AL)) {
1.1.1.29 root 11616: case 0x00: // CD-ROM - Installation Check
11617: if(REG16(BX) == 0x0000) {
11618: // MSCDEX is not installed
11619: // REG8(AL) = 0x00;
11620: } else {
11621: // GRAPHICS.COM is not installed
11622: // REG8(AL) = 0x00;
11623: }
1.1.1.22 root 11624: break;
11625: case 0xff:
1.1.1.29 root 11626: if(REG16(BX) == 0x0000) {
11627: // CORELCDX is not installed
11628: } else {
11629: 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));
11630: REG16(AX) = 0x01;
11631: m_CF = 1;
11632: }
1.1.1.22 root 11633: break;
1.1.1.21 root 11634: default:
1.1.1.22 root 11635: 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 11636: REG16(AX) = 0x01;
11637: m_CF = 1;
11638: break;
11639: }
11640: }
11641:
1.1 root 11642: inline void msdos_int_2fh_16h()
11643: {
11644: switch(REG8(AL)) {
11645: case 0x00:
1.1.1.14 root 11646: if(no_windows) {
1.1.1.29 root 11647: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
11648: // REG8(AL) = 0x00;
1.1.1.14 root 11649: } else {
1.1.1.30 root 11650: REG8(AL) = win_major_version;
11651: REG8(AH) = win_minor_version;
1.1 root 11652: }
11653: break;
1.1.1.30 root 11654: case 0x05:
11655: // from DOSBox
11656: i386_set_a20_line(1);
11657: break;
1.1.1.22 root 11658: case 0x0a:
11659: if(!no_windows) {
11660: REG16(AX) = 0x0000;
1.1.1.30 root 11661: REG8(BH) = win_major_version;
11662: REG8(BL) = win_minor_version;
1.1.1.22 root 11663: REG16(CX) = 0x0003; // enhanced
11664: }
11665: break;
1.1.1.30 root 11666: case 0x0b:
11667: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 11668: case 0x0e:
11669: case 0x0f:
1.1.1.30 root 11670: case 0x10:
1.1.1.22 root 11671: case 0x11:
11672: case 0x12:
11673: case 0x13:
11674: case 0x14:
1.1.1.30 root 11675: case 0x15:
1.1.1.33 root 11676: case 0x86:
1.1.1.22 root 11677: case 0x87:
1.1.1.30 root 11678: case 0x89:
1.1.1.33 root 11679: case 0x8a:
1.1.1.22 root 11680: // function not supported, do not clear AX
11681: break;
1.1.1.14 root 11682: case 0x80:
11683: Sleep(10);
1.1.1.35! root 11684: REQUEST_HARDWRE_UPDATE();
1.1.1.29 root 11685: REG8(AL) = 0x00;
1.1.1.14 root 11686: break;
1.1.1.33 root 11687: case 0x83:
11688: REG16(BX) = 0x01; // system vm id
11689: break;
1.1.1.22 root 11690: case 0x8e:
11691: REG16(AX) = 0x00; // failed
11692: break;
1.1.1.20 root 11693: case 0x8f:
11694: switch(REG8(DH)) {
11695: case 0x00:
11696: case 0x02:
11697: case 0x03:
11698: REG16(AX) = 0x00;
11699: break;
11700: case 0x01:
11701: REG16(AX) = 0x168f;
11702: break;
11703: }
11704: break;
1.1 root 11705: default:
1.1.1.22 root 11706: 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));
11707: REG16(AX) = 0x01;
11708: m_CF = 1;
11709: break;
11710: }
11711: }
11712:
11713: inline void msdos_int_2fh_19h()
11714: {
11715: switch(REG8(AL)) {
11716: case 0x00:
1.1.1.29 root 11717: // SHELLB.COM is not installed
11718: // REG8(AL) = 0x00;
1.1.1.22 root 11719: break;
11720: case 0x01:
11721: case 0x02:
11722: case 0x03:
11723: case 0x04:
11724: REG16(AX) = 0x01;
11725: m_CF = 1;
11726: break;
1.1.1.29 root 11727: case 0x80:
11728: // IBM ROM-DOS v4.0 is not installed
11729: // REG8(AL) = 0x00;
11730: break;
1.1.1.22 root 11731: default:
11732: 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 11733: REG16(AX) = 0x01;
1.1.1.3 root 11734: m_CF = 1;
1.1 root 11735: break;
11736: }
11737: }
11738:
11739: inline void msdos_int_2fh_1ah()
11740: {
11741: switch(REG8(AL)) {
11742: case 0x00:
1.1.1.29 root 11743: // ANSI.SYS is installed
1.1 root 11744: REG8(AL) = 0xff;
11745: break;
11746: default:
1.1.1.22 root 11747: 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));
11748: REG16(AX) = 0x01;
11749: m_CF = 1;
11750: break;
11751: }
11752: }
11753:
1.1.1.30 root 11754: inline void msdos_int_2fh_40h()
1.1.1.22 root 11755: {
11756: switch(REG8(AL)) {
11757: case 0x00:
1.1.1.30 root 11758: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
11759: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 11760: break;
11761: default:
11762: 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 11763: REG16(AX) = 0x01;
1.1.1.3 root 11764: m_CF = 1;
1.1 root 11765: break;
11766: }
11767: }
11768:
11769: inline void msdos_int_2fh_43h()
11770: {
11771: switch(REG8(AL)) {
11772: case 0x00:
1.1.1.29 root 11773: // XMS is installed ?
1.1.1.19 root 11774: #ifdef SUPPORT_XMS
11775: if(support_xms) {
11776: REG8(AL) = 0x80;
11777: } else
11778: #endif
11779: REG8(AL) = 0x00;
11780: break;
11781: case 0x10:
11782: SREG(ES) = XMS_TOP >> 4;
11783: i386_load_segment_descriptor(ES);
1.1.1.26 root 11784: REG16(BX) = 0x15;
1.1 root 11785: break;
11786: default:
1.1.1.22 root 11787: 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));
11788: REG16(AX) = 0x01;
11789: m_CF = 1;
11790: break;
11791: }
11792: }
11793:
11794: inline void msdos_int_2fh_46h()
11795: {
11796: switch(REG8(AL)) {
11797: case 0x80:
1.1.1.29 root 11798: // Windows v3.0 is not installed
11799: // REG8(AL) = 0x00;
1.1.1.22 root 11800: break;
11801: default:
11802: 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));
11803: REG16(AX) = 0x01;
11804: m_CF = 1;
11805: break;
11806: }
11807: }
11808:
11809: inline void msdos_int_2fh_48h()
11810: {
11811: switch(REG8(AL)) {
11812: case 0x00:
1.1.1.29 root 11813: // DOSKEY is not installed
11814: // REG8(AL) = 0x00;
1.1.1.22 root 11815: break;
11816: case 0x10:
11817: msdos_int_21h_0ah();
11818: REG16(AX) = 0x00;
11819: break;
11820: default:
11821: 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 11822: REG16(AX) = 0x01;
1.1.1.3 root 11823: m_CF = 1;
1.1 root 11824: break;
11825: }
11826: }
11827:
11828: inline void msdos_int_2fh_4ah()
11829: {
11830: switch(REG8(AL)) {
1.1.1.29 root 11831: #ifdef SUPPORT_HMA
11832: case 0x01: // DOS 5.0+ - Query Free HMA Space
11833: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
11834: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11835: // restore first free mcb in high memory area
11836: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11837: }
11838: int offset = 0xffff;
11839: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
11840: REG16(DI) = offset + 0x10;
11841: } else {
11842: REG16(DI) = 0xffff;
11843: }
11844: } else {
11845: // HMA is already used
11846: REG16(BX) = 0;
11847: REG16(DI) = 0xffff;
11848: }
11849: SREG(ES) = 0xffff;
11850: i386_load_segment_descriptor(ES);
11851: break;
11852: case 0x02: // DOS 5.0+ - Allocate HMA Space
11853: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
11854: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11855: // restore first free mcb in high memory area
11856: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11857: }
11858: int size = REG16(BX), offset;
11859: if((size % 16) != 0) {
11860: size &= ~15;
11861: size += 16;
11862: }
11863: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
11864: REG16(BX) = size;
11865: REG16(DI) = offset + 0x10;
11866: is_hma_used_by_int_2fh = true;
11867: } else {
11868: REG16(BX) = 0;
11869: REG16(DI) = 0xffff;
11870: }
11871: } else {
11872: // HMA is already used
11873: REG16(BX) = 0;
11874: REG16(DI) = 0xffff;
11875: }
11876: SREG(ES) = 0xffff;
11877: i386_load_segment_descriptor(ES);
11878: break;
11879: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
11880: if(REG8(DL) == 0x00) {
11881: if(!is_hma_used_by_xms) {
11882: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11883: // restore first free mcb in high memory area
11884: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11885: is_hma_used_by_int_2fh = false;
11886: }
11887: int size = REG16(BX), offset;
11888: if((size % 16) != 0) {
11889: size &= ~15;
11890: size += 16;
11891: }
11892: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
11893: // REG16(BX) = size;
11894: SREG(ES) = 0xffff;
11895: i386_load_segment_descriptor(ES);
11896: REG16(DI) = offset + 0x10;
11897: is_hma_used_by_int_2fh = true;
11898: } else {
11899: REG16(DI) = 0xffff;
11900: }
11901: } else {
11902: REG16(DI) = 0xffff;
11903: }
11904: } else if(REG8(DL) == 0x01) {
11905: if(!is_hma_used_by_xms) {
11906: int size = REG16(BX);
11907: if((size % 16) != 0) {
11908: size &= ~15;
11909: size += 16;
11910: }
11911: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
11912: // memory block address is not changed
11913: } else {
11914: REG16(DI) = 0xffff;
11915: }
11916: } else {
11917: REG16(DI) = 0xffff;
11918: }
11919: } else if(REG8(DL) == 0x02) {
11920: if(!is_hma_used_by_xms) {
11921: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11922: // restore first free mcb in high memory area
11923: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11924: is_hma_used_by_int_2fh = false;
11925: } else {
11926: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
11927: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
11928: is_hma_used_by_int_2fh = false;
11929: }
11930: }
11931: }
11932: } else {
11933: 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));
11934: REG16(AX) = 0x01;
11935: m_CF = 1;
11936: }
11937: break;
11938: case 0x04: // Windows95 - Get Start of HMA Memory Chain
11939: if(!is_hma_used_by_xms) {
11940: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11941: // restore first free mcb in high memory area
11942: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11943: is_hma_used_by_int_2fh = false;
11944: }
11945: REG16(AX) = 0x0000;
11946: SREG(ES) = 0xffff;
11947: i386_load_segment_descriptor(ES);
11948: REG16(DI) = 0x10;
11949: }
11950: break;
11951: #else
1.1 root 11952: case 0x01:
11953: case 0x02:
1.1.1.29 root 11954: // HMA is already used
1.1.1.27 root 11955: REG16(BX) = 0x0000;
1.1.1.3 root 11956: SREG(ES) = 0xffff;
11957: i386_load_segment_descriptor(ES);
1.1 root 11958: REG16(DI) = 0xffff;
11959: break;
1.1.1.19 root 11960: case 0x03:
11961: // unable to allocate
11962: REG16(DI) = 0xffff;
11963: break;
11964: case 0x04:
11965: // function not supported, do not clear AX
11966: break;
1.1.1.29 root 11967: #endif
11968: case 0x10:
11969: if(REG16(BX) == 0x0000) {
11970: // SMARTDRV is not installed
11971: } else {
11972: 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));
11973: REG16(AX) = 0x01;
11974: m_CF = 1;
11975: }
11976: break;
11977: case 0x11:
11978: if(REG16(BX) == 0x0000) {
11979: // DBLSPACE.BIN is not installed
11980: } else {
11981: 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));
11982: REG16(AX) = 0x01;
11983: m_CF = 1;
11984: }
1.1.1.22 root 11985: break;
11986: default:
11987: 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));
11988: REG16(AX) = 0x01;
11989: m_CF = 1;
11990: break;
11991: }
11992: }
11993:
11994: inline void msdos_int_2fh_4bh()
11995: {
11996: switch(REG8(AL)) {
1.1.1.24 root 11997: case 0x01:
1.1.1.22 root 11998: case 0x02:
1.1.1.29 root 11999: // Task Switcher is not installed
1.1.1.24 root 12000: break;
12001: case 0x03:
12002: // this call is available from within DOSSHELL even if the task switcher is not installed
12003: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 12004: break;
1.1.1.30 root 12005: case 0x04:
12006: REG16(BX) = 0x0000; // free switcher id successfully
12007: break;
1.1 root 12008: default:
1.1.1.22 root 12009: 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 12010: REG16(AX) = 0x01;
1.1.1.3 root 12011: m_CF = 1;
1.1 root 12012: break;
12013: }
12014: }
12015:
12016: inline void msdos_int_2fh_4fh()
12017: {
12018: switch(REG8(AL)) {
12019: case 0x00:
1.1.1.29 root 12020: // BILING is installed
1.1.1.27 root 12021: REG16(AX) = 0x0000;
12022: REG8(DL) = 0x01; // major version
12023: REG8(DH) = 0x00; // minor version
1.1 root 12024: break;
12025: case 0x01:
1.1.1.27 root 12026: REG16(AX) = 0x0000;
1.1 root 12027: REG16(BX) = active_code_page;
12028: break;
12029: default:
1.1.1.22 root 12030: 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));
12031: REG16(AX) = 0x01;
12032: m_CF = 1;
12033: break;
12034: }
12035: }
12036:
12037: inline void msdos_int_2fh_55h()
12038: {
12039: switch(REG8(AL)) {
12040: case 0x00:
12041: case 0x01:
12042: // 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));
12043: break;
12044: default:
12045: 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 12046: REG16(AX) = 0x01;
1.1.1.3 root 12047: m_CF = 1;
1.1 root 12048: break;
12049: }
12050: }
12051:
1.1.1.24 root 12052: inline void msdos_int_2fh_adh()
12053: {
12054: switch(REG8(AL)) {
12055: case 0x00:
1.1.1.29 root 12056: // DISPLAY.SYS is installed
1.1.1.24 root 12057: REG8(AL) = 0xff;
12058: REG16(BX) = 0x100; // ???
12059: break;
12060: case 0x01:
12061: active_code_page = REG16(BX);
12062: msdos_nls_tables_update();
12063: REG16(AX) = 0x01;
12064: break;
12065: case 0x02:
12066: REG16(BX) = active_code_page;
12067: break;
12068: case 0x03:
12069: // FIXME
12070: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
12071: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
12072: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
12073: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
12074: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
12075: break;
12076: case 0x80:
12077: break; // keyb.com is not installed
12078: default:
12079: 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));
12080: REG16(AX) = 0x01;
12081: m_CF = 1;
12082: break;
12083: }
12084: }
12085:
1.1 root 12086: inline void msdos_int_2fh_aeh()
12087: {
12088: switch(REG8(AL)) {
12089: case 0x00:
1.1.1.28 root 12090: // FIXME: we need to check the given command line
12091: REG8(AL) = 0x00; // the command should be executed as usual
12092: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 12093: break;
12094: case 0x01:
12095: {
12096: char command[MAX_PATH];
12097: memset(command, 0, sizeof(command));
1.1.1.3 root 12098: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 12099:
12100: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
12101: param->env_seg = 0;
12102: param->cmd_line.w.l = 44;
12103: param->cmd_line.w.h = (WORK_TOP >> 4);
12104: param->fcb1.w.l = 24;
12105: param->fcb1.w.h = (WORK_TOP >> 4);
12106: param->fcb2.w.l = 24;
12107: param->fcb2.w.h = (WORK_TOP >> 4);
12108:
12109: memset(mem + WORK_TOP + 24, 0x20, 20);
12110:
12111: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 12112: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
12113: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 12114: cmd_line->cmd[cmd_line->len] = 0x0d;
12115:
1.1.1.28 root 12116: try {
12117: msdos_process_exec(command, param, 0);
12118: } catch(...) {
12119: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 12120: }
12121: }
12122: break;
12123: default:
1.1.1.22 root 12124: 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 12125: REG16(AX) = 0x01;
1.1.1.3 root 12126: m_CF = 1;
1.1 root 12127: break;
12128: }
12129: }
12130:
1.1.1.34 root 12131: inline void msdos_int_2fh_b7h()
12132: {
12133: switch(REG8(AL)) {
12134: case 0x00:
12135: // APPEND is not installed
12136: // REG8(AL) = 0x00;
12137: break;
12138: case 0x07:
12139: // COMMAND.COM calls this service without checking APPEND is installed
12140: break;
12141: default:
12142: 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));
12143: REG16(AX) = 0x01;
12144: m_CF = 1;
12145: break;
12146: }
12147: }
12148:
1.1.1.24 root 12149: inline void msdos_int_33h_0000h()
12150: {
12151: REG16(AX) = 0xffff; // hardware/driver installed
12152: REG16(BX) = MAX_MOUSE_BUTTONS;
12153: }
12154:
12155: inline void msdos_int_33h_0001h()
12156: {
1.1.1.34 root 12157: if(mouse.hidden > 0) {
12158: mouse.hidden--;
12159: }
12160: if(mouse.hidden == 0) {
1.1.1.24 root 12161: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
12162: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
12163: }
12164: pic[1].imr &= ~0x10; // enable irq12
12165: }
12166: }
12167:
12168: inline void msdos_int_33h_0002h()
12169: {
1.1.1.34 root 12170: mouse.hidden++;
12171: // SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode & ~ENABLE_MOUSE_INPUT);
12172: pic[1].imr |= 0x10; // enable irq12
1.1.1.24 root 12173: }
12174:
12175: inline void msdos_int_33h_0003h()
12176: {
1.1.1.34 root 12177: // if(mouse.hidden > 0) {
12178: update_console_input();
12179: // }
1.1.1.24 root 12180: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 12181: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
12182: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
12183: }
12184:
12185: inline void msdos_int_33h_0004h()
12186: {
12187: mouse.position.x = REG16(CX);
12188: mouse.position.x = REG16(DX);
1.1.1.24 root 12189: }
12190:
12191: inline void msdos_int_33h_0005h()
12192: {
1.1.1.34 root 12193: // if(mouse.hidden > 0) {
12194: update_console_input();
12195: // }
1.1.1.24 root 12196: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
12197: int idx = REG16(BX);
1.1.1.34 root 12198: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff);
12199: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x));
12200: 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 12201: mouse.buttons[idx].pressed_times = 0;
12202: } else {
12203: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
12204: }
12205: REG16(AX) = mouse.get_buttons();
12206: }
12207:
12208: inline void msdos_int_33h_0006h()
12209: {
1.1.1.34 root 12210: // if(mouse.hidden > 0) {
12211: update_console_input();
12212: // }
1.1.1.24 root 12213: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
12214: int idx = REG16(BX);
1.1.1.34 root 12215: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff);
12216: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x));
12217: 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 12218: mouse.buttons[idx].released_times = 0;
12219: } else {
12220: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
12221: }
12222: REG16(AX) = mouse.get_buttons();
12223: }
12224:
12225: inline void msdos_int_33h_0007h()
12226: {
12227: mouse.min_position.x = min(REG16(CX), REG16(DX));
12228: mouse.max_position.x = max(REG16(CX), REG16(DX));
12229: }
12230:
12231: inline void msdos_int_33h_0008h()
12232: {
12233: mouse.min_position.y = min(REG16(CX), REG16(DX));
12234: mouse.max_position.y = max(REG16(CX), REG16(DX));
12235: }
12236:
12237: inline void msdos_int_33h_0009h()
12238: {
12239: mouse.hot_spot[0] = REG16(BX);
12240: mouse.hot_spot[1] = REG16(CX);
12241: }
12242:
12243: inline void msdos_int_33h_000bh()
12244: {
1.1.1.34 root 12245: // if(mouse.hidden > 0) {
12246: update_console_input();
12247: // }
1.1.1.24 root 12248: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
12249: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
12250: mouse.prev_position.x = mouse.position.x;
12251: mouse.prev_position.y = mouse.position.y;
12252: REG16(CX) = dx;
12253: REG16(DX) = dy;
12254: }
12255:
12256: inline void msdos_int_33h_000ch()
12257: {
12258: mouse.call_mask = REG16(CX);
12259: mouse.call_addr.w.l = REG16(DX);
12260: mouse.call_addr.w.h = SREG(ES);
12261: }
12262:
12263: inline void msdos_int_33h_000fh()
12264: {
12265: mouse.mickey.x = REG16(CX);
12266: mouse.mickey.y = REG16(DX);
12267: }
12268:
12269: inline void msdos_int_33h_0011h()
12270: {
12271: REG16(AX) = 0xffff;
12272: REG16(BX) = MAX_MOUSE_BUTTONS;
12273: }
12274:
12275: inline void msdos_int_33h_0014h()
12276: {
12277: UINT16 old_mask = mouse.call_mask;
12278: UINT16 old_ofs = mouse.call_addr.w.l;
12279: UINT16 old_seg = mouse.call_addr.w.h;
12280:
12281: mouse.call_mask = REG16(CX);
12282: mouse.call_addr.w.l = REG16(DX);
12283: mouse.call_addr.w.h = SREG(ES);
12284:
12285: REG16(CX) = old_mask;
12286: REG16(DX) = old_ofs;
12287: SREG(ES) = old_seg;
12288: i386_load_segment_descriptor(ES);
12289: }
12290:
12291: inline void msdos_int_33h_0015h()
12292: {
12293: REG16(BX) = sizeof(mouse);
12294: }
12295:
12296: inline void msdos_int_33h_0016h()
12297: {
12298: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
12299: }
12300:
12301: inline void msdos_int_33h_0017h()
12302: {
12303: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
12304: }
12305:
12306: inline void msdos_int_33h_001ah()
12307: {
12308: mouse.sensitivity[0] = REG16(BX);
12309: mouse.sensitivity[1] = REG16(CX);
12310: mouse.sensitivity[2] = REG16(DX);
12311: }
12312:
12313: inline void msdos_int_33h_001bh()
12314: {
12315: REG16(BX) = mouse.sensitivity[0];
12316: REG16(CX) = mouse.sensitivity[1];
12317: REG16(DX) = mouse.sensitivity[2];
12318: }
12319:
12320: inline void msdos_int_33h_001dh()
12321: {
12322: mouse.display_page = REG16(BX);
12323: }
12324:
12325: inline void msdos_int_33h_001eh()
12326: {
12327: REG16(BX) = mouse.display_page;
12328: }
12329:
1.1.1.34 root 12330: inline void msdos_int_33h_001fh()
12331: {
12332: // from DOSBox
12333: REG16(BX) = 0x0000;
12334: SREG(ES) = 0x0000;
12335: i386_load_segment_descriptor(ES);
12336: mouse.enabled = false;
12337: mouse.old_hidden = mouse.hidden;
12338: mouse.hidden = 1;
12339: }
12340:
12341: inline void msdos_int_33h_0020h()
12342: {
12343: // from DOSBox
12344: mouse.enabled = true;
12345: mouse.hidden = mouse.old_hidden;
12346: }
12347:
1.1.1.24 root 12348: inline void msdos_int_33h_0021h()
12349: {
12350: REG16(AX) = 0xffff;
12351: REG16(BX) = MAX_MOUSE_BUTTONS;
12352: }
12353:
12354: inline void msdos_int_33h_0022h()
12355: {
12356: mouse.language = REG16(BX);
12357: }
12358:
12359: inline void msdos_int_33h_0023h()
12360: {
12361: REG16(BX) = mouse.language;
12362: }
12363:
12364: inline void msdos_int_33h_0024h()
12365: {
12366: REG16(BX) = 0x0805; // V8.05
12367: REG16(CX) = 0x0400; // PS/2
12368: }
12369:
12370: inline void msdos_int_33h_0026h()
12371: {
12372: REG16(BX) = 0x0000;
12373: REG16(CX) = mouse.max_position.x;
12374: REG16(DX) = mouse.max_position.y;
12375: }
12376:
12377: inline void msdos_int_33h_002ah()
12378: {
1.1.1.34 root 12379: REG16(AX) = -mouse.hidden;
1.1.1.24 root 12380: REG16(BX) = mouse.hot_spot[0];
12381: REG16(CX) = mouse.hot_spot[1];
12382: REG16(DX) = 4; // PS/2
12383: }
12384:
12385: inline void msdos_int_33h_0031h()
12386: {
12387: REG16(AX) = mouse.min_position.x;
12388: REG16(BX) = mouse.min_position.y;
12389: REG16(CX) = mouse.max_position.x;
12390: REG16(DX) = mouse.max_position.y;
12391: }
12392:
12393: inline void msdos_int_33h_0032h()
12394: {
12395: REG16(AX) = 0;
12396: // REG16(AX) |= 0x8000; // 0025h
12397: REG16(AX) |= 0x4000; // 0026h
12398: // REG16(AX) |= 0x2000; // 0027h
12399: // REG16(AX) |= 0x1000; // 0028h
12400: // REG16(AX) |= 0x0800; // 0029h
12401: REG16(AX) |= 0x0400; // 002ah
12402: // REG16(AX) |= 0x0200; // 002bh
12403: // REG16(AX) |= 0x0100; // 002ch
12404: // REG16(AX) |= 0x0080; // 002dh
12405: // REG16(AX) |= 0x0040; // 002eh
12406: REG16(AX) |= 0x0020; // 002fh
12407: // REG16(AX) |= 0x0010; // 0030h
12408: REG16(AX) |= 0x0008; // 0031h
12409: REG16(AX) |= 0x0004; // 0032h
12410: // REG16(AX) |= 0x0002; // 0033h
12411: // REG16(AX) |= 0x0001; // 0034h
12412: }
12413:
1.1.1.19 root 12414: inline void msdos_int_67h_40h()
12415: {
12416: if(!support_ems) {
12417: REG8(AH) = 0x84;
12418: } else {
12419: REG8(AH) = 0x00;
12420: }
12421: }
12422:
12423: inline void msdos_int_67h_41h()
12424: {
12425: if(!support_ems) {
12426: REG8(AH) = 0x84;
12427: } else {
12428: REG8(AH) = 0x00;
12429: REG16(BX) = EMS_TOP >> 4;
12430: }
12431: }
12432:
12433: inline void msdos_int_67h_42h()
12434: {
12435: if(!support_ems) {
12436: REG8(AH) = 0x84;
12437: } else {
12438: REG8(AH) = 0x00;
12439: REG16(BX) = free_ems_pages;
12440: REG16(DX) = MAX_EMS_PAGES;
12441: }
12442: }
12443:
12444: inline void msdos_int_67h_43h()
12445: {
12446: if(!support_ems) {
12447: REG8(AH) = 0x84;
12448: } else if(REG16(BX) > MAX_EMS_PAGES) {
12449: REG8(AH) = 0x87;
12450: } else if(REG16(BX) > free_ems_pages) {
12451: REG8(AH) = 0x88;
12452: } else if(REG16(BX) == 0) {
12453: REG8(AH) = 0x89;
12454: } else {
1.1.1.31 root 12455: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12456: if(!ems_handles[i].allocated) {
12457: ems_allocate_pages(i, REG16(BX));
12458: REG8(AH) = 0x00;
12459: REG16(DX) = i;
12460: return;
12461: }
12462: }
12463: REG8(AH) = 0x85;
12464: }
12465: }
12466:
12467: inline void msdos_int_67h_44h()
12468: {
12469: if(!support_ems) {
12470: REG8(AH) = 0x84;
1.1.1.31 root 12471: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12472: REG8(AH) = 0x83;
12473: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
12474: REG8(AH) = 0x8a;
12475: // } else if(!(REG8(AL) < 4)) {
12476: // REG8(AH) = 0x8b;
12477: } else if(REG16(BX) == 0xffff) {
12478: ems_unmap_page(REG8(AL) & 3);
12479: REG8(AH) = 0x00;
12480: } else {
12481: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
12482: REG8(AH) = 0x00;
12483: }
12484: }
12485:
12486: inline void msdos_int_67h_45h()
12487: {
12488: if(!support_ems) {
12489: REG8(AH) = 0x84;
1.1.1.31 root 12490: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12491: REG8(AH) = 0x83;
12492: } else {
12493: ems_release_pages(REG16(DX));
12494: REG8(AH) = 0x00;
12495: }
12496: }
12497:
12498: inline void msdos_int_67h_46h()
12499: {
12500: if(!support_ems) {
12501: REG8(AH) = 0x84;
12502: } else {
1.1.1.29 root 12503: // REG16(AX) = 0x0032; // EMS 3.2
12504: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 12505: }
12506: }
12507:
12508: inline void msdos_int_67h_47h()
12509: {
12510: // NOTE: the map data should be stored in the specified ems page, not process data
12511: process_t *process = msdos_process_info_get(current_psp);
12512:
12513: if(!support_ems) {
12514: REG8(AH) = 0x84;
1.1.1.31 root 12515: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12516: // REG8(AH) = 0x83;
12517: } else if(process->ems_pages_stored) {
12518: REG8(AH) = 0x8d;
12519: } else {
12520: for(int i = 0; i < 4; i++) {
12521: process->ems_pages[i].handle = ems_pages[i].handle;
12522: process->ems_pages[i].page = ems_pages[i].page;
12523: process->ems_pages[i].mapped = ems_pages[i].mapped;
12524: }
12525: process->ems_pages_stored = true;
12526: REG8(AH) = 0x00;
12527: }
12528: }
12529:
12530: inline void msdos_int_67h_48h()
12531: {
12532: // NOTE: the map data should be restored from the specified ems page, not process data
12533: process_t *process = msdos_process_info_get(current_psp);
12534:
12535: if(!support_ems) {
12536: REG8(AH) = 0x84;
1.1.1.31 root 12537: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12538: // REG8(AH) = 0x83;
12539: } else if(!process->ems_pages_stored) {
12540: REG8(AH) = 0x8e;
12541: } else {
12542: for(int i = 0; i < 4; i++) {
12543: if(process->ems_pages[i].mapped) {
12544: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
12545: } else {
12546: ems_unmap_page(i);
12547: }
12548: }
12549: process->ems_pages_stored = false;
12550: REG8(AH) = 0x00;
12551: }
12552: }
12553:
12554: inline void msdos_int_67h_4bh()
12555: {
12556: if(!support_ems) {
12557: REG8(AH) = 0x84;
12558: } else {
12559: REG8(AH) = 0x00;
12560: REG16(BX) = 0;
1.1.1.31 root 12561: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12562: if(ems_handles[i].allocated) {
12563: REG16(BX)++;
12564: }
12565: }
12566: }
12567: }
12568:
12569: inline void msdos_int_67h_4ch()
12570: {
12571: if(!support_ems) {
12572: REG8(AH) = 0x84;
1.1.1.31 root 12573: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12574: REG8(AH) = 0x83;
12575: } else {
12576: REG8(AH) = 0x00;
12577: REG16(BX) = ems_handles[REG16(DX)].pages;
12578: }
12579: }
12580:
12581: inline void msdos_int_67h_4dh()
12582: {
12583: if(!support_ems) {
12584: REG8(AH) = 0x84;
12585: } else {
12586: REG8(AH) = 0x00;
12587: REG16(BX) = 0;
1.1.1.31 root 12588: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12589: if(ems_handles[i].allocated) {
12590: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
12591: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
12592: REG16(BX)++;
12593: }
12594: }
12595: }
12596: }
12597:
1.1.1.20 root 12598: inline void msdos_int_67h_4eh()
12599: {
12600: if(!support_ems) {
12601: REG8(AH) = 0x84;
12602: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
12603: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
12604: // save page map
12605: for(int i = 0; i < 4; i++) {
12606: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
12607: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
12608: }
12609: }
12610: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
12611: // restore page map
12612: for(int i = 0; i < 4; i++) {
12613: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
12614: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
12615:
1.1.1.31 root 12616: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 12617: ems_map_page(i, handle, page);
12618: } else {
12619: ems_unmap_page(i);
12620: }
12621: }
12622: }
12623: REG8(AH) = 0x00;
12624: } else if(REG8(AL) == 0x03) {
12625: REG8(AH) = 0x00;
1.1.1.21 root 12626: REG8(AL) = 4 * 4;
12627: } else {
1.1.1.22 root 12628: 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 12629: REG8(AH) = 0x8f;
12630: }
12631: }
12632:
12633: inline void msdos_int_67h_4fh()
12634: {
12635: if(!support_ems) {
12636: REG8(AH) = 0x84;
12637: } else if(REG8(AL) == 0x00) {
12638: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
12639:
12640: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
12641: for(int i = 0; i < count; i++) {
12642: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
12643: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
12644:
12645: // if(!(physical < 4)) {
12646: // REG8(AH) = 0x8b;
12647: // return;
12648: // }
12649: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
12650: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
12651: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
12652: }
12653: REG8(AH) = 0x00;
12654: } else if(REG8(AL) == 0x01) {
12655: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
12656:
12657: for(int i = 0; i < count; i++) {
12658: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
12659: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
12660: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
12661: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
12662:
12663: // if(!(physical < 4)) {
12664: // REG8(AH) = 0x8b;
12665: // return;
12666: // } else
1.1.1.31 root 12667: if(!(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
1.1.1.21 root 12668: REG8(AH) = 0x83;
12669: return;
12670: } else if(logical == 0xffff) {
12671: ems_unmap_page(physical & 3);
12672: } else if(logical < ems_handles[handle].pages) {
12673: ems_map_page(physical & 3, handle, logical);
12674: } else {
12675: REG8(AH) = 0x8a;
12676: return;
12677: }
12678: }
12679: REG8(AH) = 0x00;
12680: } else if(REG8(AL) == 0x02) {
12681: REG8(AH) = 0x00;
12682: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 12683: } else {
1.1.1.22 root 12684: 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 12685: REG8(AH) = 0x8f;
12686: }
12687: }
12688:
12689: inline void msdos_int_67h_50h()
12690: {
12691: if(!support_ems) {
12692: REG8(AH) = 0x84;
1.1.1.31 root 12693: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 12694: REG8(AH) = 0x83;
12695: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
12696: for(int i = 0; i < REG16(CX); i++) {
12697: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
12698: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
12699:
12700: if(REG8(AL) == 0x01) {
12701: physical = ((physical << 4) - EMS_TOP) / 0x4000;
12702: }
12703: // if(!(physical < 4)) {
12704: // REG8(AH) = 0x8b;
12705: // return;
12706: // } else
12707: if(logical == 0xffff) {
12708: ems_unmap_page(physical & 3);
12709: } else if(logical < ems_handles[REG16(DX)].pages) {
12710: ems_map_page(physical & 3, REG16(DX), logical);
12711: } else {
12712: REG8(AH) = 0x8a;
12713: return;
12714: }
12715: }
12716: REG8(AH) = 0x00;
12717: } else {
1.1.1.22 root 12718: 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 12719: REG8(AH) = 0x8f;
12720: }
12721: }
12722:
1.1.1.19 root 12723: inline void msdos_int_67h_51h()
12724: {
12725: if(!support_ems) {
12726: REG8(AH) = 0x84;
1.1.1.31 root 12727: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12728: REG8(AH) = 0x83;
12729: } else if(REG16(BX) > MAX_EMS_PAGES) {
12730: REG8(AH) = 0x87;
12731: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
12732: REG8(AH) = 0x88;
12733: } else {
12734: ems_reallocate_pages(REG16(DX), REG16(BX));
12735: REG8(AH) = 0x00;
12736: }
12737: }
12738:
1.1.1.20 root 12739: inline void msdos_int_67h_52h()
12740: {
12741: if(!support_ems) {
12742: REG8(AH) = 0x84;
1.1.1.31 root 12743: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
12744: // REG8(AH) = 0x83;
1.1.1.20 root 12745: } else if(REG8(AL) == 0x00) {
12746: REG8(AL) = 0x00; // handle is volatile
12747: REG8(AH) = 0x00;
12748: } else if(REG8(AL) == 0x01) {
12749: if(REG8(BL) == 0x00) {
12750: REG8(AH) = 0x00;
12751: } else {
12752: REG8(AH) = 0x90; // undefined attribute type
12753: }
12754: } else if(REG8(AL) == 0x02) {
12755: REG8(AL) = 0x00; // only volatile handles supported
12756: REG8(AH) = 0x00;
12757: } else {
1.1.1.22 root 12758: 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 12759: REG8(AH) = 0x8f;
12760: }
12761: }
12762:
1.1.1.19 root 12763: inline void msdos_int_67h_53h()
12764: {
12765: if(!support_ems) {
12766: REG8(AH) = 0x84;
1.1.1.31 root 12767: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12768: REG8(AH) = 0x83;
12769: } else if(REG8(AL) == 0x00) {
12770: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
12771: REG8(AH) = 0x00;
12772: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 12773: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12774: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
12775: REG8(AH) = 0xa1;
12776: return;
12777: }
12778: }
12779: REG8(AH) = 0x00;
12780: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
12781: } else {
1.1.1.22 root 12782: 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 12783: REG8(AH) = 0x8f;
1.1.1.19 root 12784: }
12785: }
12786:
12787: inline void msdos_int_67h_54h()
12788: {
12789: if(!support_ems) {
12790: REG8(AH) = 0x84;
12791: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 12792: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12793: if(ems_handles[i].allocated) {
12794: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
12795: } else {
12796: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
12797: }
12798: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
12799: }
12800: REG8(AH) = 0x00;
12801: REG8(AL) = MAX_EMS_HANDLES;
12802: } else if(REG8(AL) == 0x01) {
12803: REG8(AH) = 0xa0; // not found
1.1.1.31 root 12804: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12805: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
12806: REG8(AH) = 0x00;
12807: REG16(DX) = i;
12808: break;
12809: }
12810: }
12811: } else if(REG8(AL) == 0x02) {
12812: REG8(AH) = 0x00;
12813: REG16(BX) = MAX_EMS_HANDLES;
12814: } else {
1.1.1.22 root 12815: 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 12816: REG8(AH) = 0x8f;
12817: }
12818: }
12819:
12820: inline void msdos_int_67h_57h_tmp()
12821: {
12822: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
12823: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
12824: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
12825: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
12826: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
12827: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
12828: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
12829: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
12830: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
12831:
1.1.1.32 root 12832: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 12833: UINT32 src_addr, dest_addr;
12834: UINT32 src_addr_max, dest_addr_max;
12835:
12836: if(src_type == 0) {
12837: src_buffer = mem;
12838: src_addr = (src_seg << 4) + src_ofs;
12839: src_addr_max = MAX_MEM;
12840: } else {
1.1.1.31 root 12841: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 12842: REG8(AH) = 0x83;
12843: return;
12844: } else if(!(src_seg < ems_handles[src_handle].pages)) {
12845: REG8(AH) = 0x8a;
12846: return;
12847: }
1.1.1.32 root 12848: if(ems_handles[src_handle].buffer != NULL) {
12849: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
12850: }
1.1.1.20 root 12851: src_addr = src_ofs;
1.1.1.32 root 12852: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 12853: }
12854: if(dest_type == 0) {
12855: dest_buffer = mem;
12856: dest_addr = (dest_seg << 4) + dest_ofs;
12857: dest_addr_max = MAX_MEM;
12858: } else {
1.1.1.31 root 12859: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 12860: REG8(AH) = 0x83;
12861: return;
12862: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
12863: REG8(AH) = 0x8a;
12864: return;
12865: }
1.1.1.32 root 12866: if(ems_handles[dest_handle].buffer != NULL) {
12867: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
12868: }
1.1.1.20 root 12869: dest_addr = dest_ofs;
1.1.1.32 root 12870: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 12871: }
1.1.1.32 root 12872: if(src_buffer != NULL && dest_buffer != NULL) {
12873: for(int i = 0; i < copy_length; i++) {
12874: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
12875: if(REG8(AL) == 0x00) {
12876: dest_buffer[dest_addr++] = src_buffer[src_addr++];
12877: } else if(REG8(AL) == 0x01) {
12878: UINT8 tmp = dest_buffer[dest_addr];
12879: dest_buffer[dest_addr++] = src_buffer[src_addr];
12880: src_buffer[src_addr++] = tmp;
12881: }
12882: } else {
12883: REG8(AH) = 0x93;
12884: return;
1.1.1.20 root 12885: }
12886: }
1.1.1.32 root 12887: REG8(AH) = 0x00;
12888: } else {
12889: REG8(AH) = 0x80;
1.1.1.20 root 12890: }
12891: }
12892:
12893: inline void msdos_int_67h_57h()
12894: {
12895: if(!support_ems) {
12896: REG8(AH) = 0x84;
12897: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
12898: struct {
12899: UINT16 handle;
12900: UINT16 page;
12901: bool mapped;
12902: } tmp_pages[4];
12903:
12904: // unmap pages to copy memory data to ems buffer
12905: for(int i = 0; i < 4; i++) {
12906: tmp_pages[i].handle = ems_pages[i].handle;
12907: tmp_pages[i].page = ems_pages[i].page;
12908: tmp_pages[i].mapped = ems_pages[i].mapped;
12909: ems_unmap_page(i);
12910: }
12911:
12912: // run move/exchange operation
12913: msdos_int_67h_57h_tmp();
12914:
12915: // restore unmapped pages
12916: for(int i = 0; i < 4; i++) {
12917: if(tmp_pages[i].mapped) {
12918: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
12919: }
12920: }
12921: } else {
1.1.1.22 root 12922: 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 12923: REG8(AH) = 0x8f;
12924: }
12925: }
12926:
12927: inline void msdos_int_67h_58h()
12928: {
12929: if(!support_ems) {
12930: REG8(AH) = 0x84;
12931: } else if(REG8(AL) == 0x00) {
12932: for(int i = 0; i < 4; i++) {
1.1.1.30 root 12933: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
12934: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 12935: }
12936: REG8(AH) = 0x00;
12937: REG16(CX) = 4;
12938: } else if(REG8(AL) == 0x01) {
12939: REG8(AH) = 0x00;
12940: REG16(CX) = 4;
12941: } else {
1.1.1.22 root 12942: 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 12943: REG8(AH) = 0x8f;
12944: }
12945: }
12946:
12947: inline void msdos_int_67h_5ah()
12948: {
12949: if(!support_ems) {
1.1.1.19 root 12950: REG8(AH) = 0x84;
1.1.1.20 root 12951: } else if(REG16(BX) > MAX_EMS_PAGES) {
12952: REG8(AH) = 0x87;
12953: } else if(REG16(BX) > free_ems_pages) {
12954: REG8(AH) = 0x88;
12955: // } else if(REG16(BX) == 0) {
12956: // REG8(AH) = 0x89;
12957: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 12958: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 12959: if(!ems_handles[i].allocated) {
12960: ems_allocate_pages(i, REG16(BX));
12961: REG8(AH) = 0x00;
12962: REG16(DX) = i;
12963: return;
12964: }
12965: }
12966: REG8(AH) = 0x85;
12967: } else {
1.1.1.22 root 12968: 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 12969: REG8(AH) = 0x8f;
1.1.1.19 root 12970: }
12971: }
12972:
1.1.1.30 root 12973: inline void msdos_int_67h_deh()
12974: {
12975: REG8(AH) = 0x84;
12976: }
12977:
1.1.1.19 root 12978: #ifdef SUPPORT_XMS
12979:
1.1.1.32 root 12980: void msdos_xms_init()
1.1.1.26 root 12981: {
1.1.1.30 root 12982: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
12983: emb_handle_top->address = EMB_TOP;
12984: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 12985: xms_a20_local_enb_count = 0;
12986: }
12987:
1.1.1.32 root 12988: void msdos_xms_finish()
12989: {
12990: msdos_xms_release();
12991: }
12992:
12993: void msdos_xms_release()
1.1.1.30 root 12994: {
12995: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
12996: emb_handle_t *next_handle = emb_handle->next;
12997: free(emb_handle);
12998: emb_handle = next_handle;
12999: }
13000: }
13001:
13002: emb_handle_t *msdos_xms_get_emb_handle(int handle)
13003: {
13004: if(handle != 0) {
13005: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13006: if(emb_handle->handle == handle) {
13007: return(emb_handle);
13008: }
13009: }
13010: }
13011: return(NULL);
13012: }
13013:
13014: int msdos_xms_get_unused_emb_handle_id()
13015: {
13016: for(int handle = 1;; handle++) {
13017: if(msdos_xms_get_emb_handle(handle) == NULL) {
13018: return(handle);
13019: }
13020: }
13021: return(0);
13022: }
13023:
13024: int msdos_xms_get_unused_emb_handle_count()
13025: {
13026: int count = 64; //255;
13027:
13028: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13029: if(emb_handle->handle != 0) {
13030: if(--count == 1) {
13031: break;
13032: }
13033: }
13034: }
13035: return(count);
13036: }
13037:
13038: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
13039: {
13040: if(emb_handle->size_kb > size_kb) {
13041: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
13042:
13043: new_handle->address = emb_handle->address + size_kb * 1024;
13044: new_handle->size_kb = emb_handle->size_kb - size_kb;
13045: emb_handle->size_kb = size_kb;
13046:
13047: new_handle->prev = emb_handle;
13048: new_handle->next = emb_handle->next;
13049: if(emb_handle->next != NULL) {
13050: emb_handle->next->prev = new_handle;
13051: }
13052: emb_handle->next = new_handle;
13053: }
13054: }
13055:
13056: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
13057: {
13058: emb_handle_t *next_handle = emb_handle->next;
13059:
13060: if(next_handle != NULL) {
13061: emb_handle->size_kb += next_handle->size_kb;
13062:
13063: if(next_handle->next != NULL) {
13064: next_handle->next->prev = emb_handle;
13065: }
13066: emb_handle->next = next_handle->next;
13067: free(next_handle);
13068: }
13069: }
13070:
13071: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
13072: {
13073: emb_handle_t *target_handle = NULL;
13074:
13075: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13076: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
13077: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
13078: target_handle = emb_handle;
13079: }
13080: }
13081: }
13082: if(target_handle != NULL) {
13083: if(target_handle->size_kb > size_kb) {
13084: msdos_xms_split_emb_handle(target_handle, size_kb);
13085: }
13086: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
13087: return(target_handle);
13088: }
13089: return(NULL);
13090: }
13091:
13092: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
13093: {
13094: emb_handle_t *prev_handle = emb_handle->prev;
13095: emb_handle_t *next_handle = emb_handle->next;
13096:
13097: if(prev_handle != NULL && prev_handle->handle == 0) {
13098: msdos_xms_combine_emb_handles(prev_handle);
13099: emb_handle = prev_handle;
13100: }
13101: if(next_handle != NULL && next_handle->handle == 0) {
13102: msdos_xms_combine_emb_handles(emb_handle);
13103: }
13104: emb_handle->handle = 0;
13105: }
13106:
1.1.1.19 root 13107: inline void msdos_call_xms_00h()
13108: {
1.1.1.29 root 13109: #if defined(HAS_I386)
13110: REG16(AX) = 0x0300; // V3.00 (XMS Version)
13111: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
13112: #else
13113: REG16(AX) = 0x0200; // V2.00 (XMS Version)
13114: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
13115: #endif
13116: // REG16(DX) = 0x0000; // HMA does not exist
13117: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 13118: }
13119:
13120: inline void msdos_call_xms_01h()
13121: {
1.1.1.29 root 13122: if(REG8(AL) == 0x40) {
13123: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
13124: // DX=KB free extended memory returned by last call of function 08h
13125: REG16(AX) = 0x0000;
13126: REG8(BL) = 0x91;
13127: REG16(DX) = xms_dx_after_call_08h;
13128: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
13129: REG16(AX) = 0x0000;
13130: REG8(BL) = 0x81; // Vdisk was detected
13131: #ifdef SUPPORT_HMA
13132: } else if(is_hma_used_by_int_2fh) {
13133: REG16(AX) = 0x0000;
13134: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
13135: } else if(is_hma_used_by_xms) {
13136: REG16(AX) = 0x0000;
13137: REG8(BL) = 0x91; // HMA is already in use
13138: } else {
13139: REG16(AX) = 0x0001;
13140: is_hma_used_by_xms = true;
13141: #else
13142: } else {
13143: REG16(AX) = 0x0000;
13144: REG8(BL) = 0x91; // HMA is already in use
13145: #endif
13146: }
1.1.1.19 root 13147: }
13148:
13149: inline void msdos_call_xms_02h()
13150: {
1.1.1.29 root 13151: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
13152: REG16(AX) = 0x0000;
13153: REG8(BL) = 0x81; // Vdisk was detected
13154: #ifdef SUPPORT_HMA
13155: } else if(is_hma_used_by_int_2fh) {
13156: REG16(AX) = 0x0000;
13157: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
13158: } else if(!is_hma_used_by_xms) {
13159: REG16(AX) = 0x0000;
13160: REG8(BL) = 0x93; // HMA is not allocated
13161: } else {
13162: REG16(AX) = 0x0001;
13163: is_hma_used_by_xms = false;
13164: // restore first free mcb in high memory area
13165: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13166: #else
13167: } else {
13168: REG16(AX) = 0x0000;
13169: REG8(BL) = 0x91; // HMA is already in use
13170: #endif
13171: }
1.1.1.19 root 13172: }
13173:
13174: inline void msdos_call_xms_03h()
13175: {
13176: i386_set_a20_line(1);
13177: REG16(AX) = 0x0001;
13178: REG8(BL) = 0x00;
13179: }
13180:
13181: inline void msdos_call_xms_04h()
13182: {
1.1.1.21 root 13183: i386_set_a20_line(0);
13184: REG16(AX) = 0x0001;
13185: REG8(BL) = 0x00;
1.1.1.19 root 13186: }
13187:
13188: inline void msdos_call_xms_05h()
13189: {
13190: i386_set_a20_line(1);
13191: REG16(AX) = 0x0001;
13192: REG8(BL) = 0x00;
1.1.1.21 root 13193: xms_a20_local_enb_count++;
1.1.1.19 root 13194: }
13195:
13196: void msdos_call_xms_06h()
13197: {
1.1.1.21 root 13198: if(xms_a20_local_enb_count > 0) {
13199: xms_a20_local_enb_count--;
13200: }
13201: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 13202: i386_set_a20_line(0);
1.1.1.21 root 13203: }
13204: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 13205: REG16(AX) = 0x0000;
13206: REG8(BL) = 0x94;
1.1.1.21 root 13207: } else {
13208: REG16(AX) = 0x0001;
13209: REG8(BL) = 0x00;
1.1.1.19 root 13210: }
13211: }
13212:
13213: inline void msdos_call_xms_07h()
13214: {
13215: REG16(AX) = (m_a20_mask >> 20) & 1;
13216: REG8(BL) = 0x00;
13217: }
13218:
13219: inline void msdos_call_xms_08h()
13220: {
13221: REG16(AX) = REG16(DX) = 0x0000;
13222:
1.1.1.30 root 13223: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13224: if(emb_handle->handle == 0) {
13225: if(REG16(AX) < emb_handle->size_kb) {
13226: REG16(AX) = emb_handle->size_kb;
1.1.1.19 root 13227: }
1.1.1.30 root 13228: REG16(DX) += emb_handle->size_kb;
1.1.1.19 root 13229: }
13230: }
13231:
13232: if(REG16(AX) == 0 && REG16(DX) == 0) {
13233: REG8(BL) = 0xa0;
13234: } else {
13235: REG8(BL) = 0x00;
13236: }
1.1.1.29 root 13237: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 13238: }
13239:
1.1.1.30 root 13240: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 13241: {
1.1.1.30 root 13242: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
13243:
13244: if(emb_handle != NULL) {
13245: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
13246:
13247: REG16(AX) = 0x0001;
13248: REG16(DX) = emb_handle->handle;
13249: REG8(BL) = 0x00;
13250: } else {
13251: REG16(AX) = REG16(DX) = 0x0000;
13252: REG8(BL) = 0xa0;
1.1.1.19 root 13253: }
1.1.1.30 root 13254: }
13255:
13256: inline void msdos_call_xms_09h()
13257: {
13258: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 13259: }
13260:
13261: inline void msdos_call_xms_0ah()
13262: {
1.1.1.30 root 13263: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13264:
13265: if(emb_handle == NULL) {
1.1.1.19 root 13266: REG16(AX) = 0x0000;
13267: REG8(BL) = 0xa2;
1.1.1.30 root 13268: } else if(emb_handle->lock > 0) {
1.1.1.19 root 13269: REG16(AX) = 0x0000;
13270: REG8(BL) = 0xab;
13271: } else {
1.1.1.30 root 13272: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 13273:
13274: REG16(AX) = 0x0001;
13275: REG8(BL) = 0x00;
13276: }
13277: }
13278:
13279: inline void msdos_call_xms_0bh()
13280: {
13281: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
13282: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
13283: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
13284: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
13285: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
13286:
13287: UINT8 *src_buffer, *dest_buffer;
13288: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 13289: emb_handle_t *emb_handle;
1.1.1.19 root 13290:
13291: if(src_handle == 0) {
13292: src_buffer = mem;
13293: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
13294: src_addr_max = MAX_MEM;
1.1.1.30 root 13295:
1.1.1.19 root 13296: } else {
1.1.1.30 root 13297: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 13298: REG16(AX) = 0x0000;
13299: REG8(BL) = 0xa3;
13300: return;
13301: }
1.1.1.30 root 13302: src_buffer = mem + emb_handle->address;
13303: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 13304: }
13305: if(dest_handle == 0) {
13306: dest_buffer = mem;
13307: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
13308: dest_addr_max = MAX_MEM;
13309: } else {
1.1.1.30 root 13310: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 13311: REG16(AX) = 0x0000;
13312: REG8(BL) = 0xa5;
13313: return;
13314: }
1.1.1.30 root 13315: dest_buffer = mem + emb_handle->address;
13316: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 13317: }
13318: for(int i = 0; i < copy_length; i++) {
13319: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
13320: dest_buffer[dest_addr++] = src_buffer[src_addr++];
13321: } else {
13322: break;
13323: }
13324: }
13325: REG16(AX) = 0x0001;
13326: REG8(BL) = 0x00;
13327: }
13328:
13329: inline void msdos_call_xms_0ch()
13330: {
1.1.1.30 root 13331: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13332:
13333: if(emb_handle == NULL) {
1.1.1.19 root 13334: REG16(AX) = 0x0000;
13335: REG8(BL) = 0xa2;
13336: } else {
1.1.1.30 root 13337: emb_handle->lock++;
1.1.1.19 root 13338: REG16(AX) = 0x0001;
13339: REG8(BL) = 0x00;
1.1.1.30 root 13340: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
13341: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 13342: }
13343: }
13344:
13345: inline void msdos_call_xms_0dh()
13346: {
1.1.1.30 root 13347: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13348:
13349: if(emb_handle == NULL) {
1.1.1.19 root 13350: REG16(AX) = 0x0000;
13351: REG8(BL) = 0xa2;
1.1.1.30 root 13352: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 13353: REG16(AX) = 0x0000;
13354: REG8(BL) = 0xaa;
13355: } else {
1.1.1.30 root 13356: emb_handle->lock--;
1.1.1.19 root 13357: REG16(AX) = 0x0001;
13358: REG8(BL) = 0x00;
13359: }
13360: }
13361:
13362: inline void msdos_call_xms_0eh()
13363: {
1.1.1.30 root 13364: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13365:
13366: if(emb_handle == NULL) {
1.1.1.19 root 13367: REG16(AX) = 0x0000;
13368: REG8(BL) = 0xa2;
13369: } else {
13370: REG16(AX) = 0x0001;
1.1.1.30 root 13371: REG8(BH) = emb_handle->lock;
13372: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
13373: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 13374: }
13375: }
13376:
1.1.1.30 root 13377: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 13378: {
1.1.1.30 root 13379: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13380:
13381: if(emb_handle == NULL) {
1.1.1.19 root 13382: REG16(AX) = 0x0000;
13383: REG8(BL) = 0xa2;
1.1.1.30 root 13384: } else if(emb_handle->lock > 0) {
1.1.1.19 root 13385: REG16(AX) = 0x0000;
13386: REG8(BL) = 0xab;
13387: } else {
1.1.1.30 root 13388: if(emb_handle->size_kb < size_kb) {
13389: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
13390: msdos_xms_combine_emb_handles(emb_handle);
13391: if(emb_handle->size_kb > size_kb) {
13392: msdos_xms_split_emb_handle(emb_handle, size_kb);
13393: }
13394: } else {
13395: int old_handle = emb_handle->handle;
13396: int old_size_kb = emb_handle->size_kb;
13397: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
13398:
13399: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
13400: msdos_xms_free_emb_handle(emb_handle);
13401:
13402: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
13403: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
13404: }
13405: emb_handle->handle = old_handle;
13406: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
13407: free(buffer);
13408: }
13409: } else if(emb_handle->size_kb > size_kb) {
13410: msdos_xms_split_emb_handle(emb_handle, size_kb);
13411: }
13412: if(emb_handle->size_kb != size_kb) {
13413: REG16(AX) = 0x0000;
13414: REG8(BL) = 0xa0;
13415: } else {
13416: REG16(AX) = 0x0001;
13417: REG8(BL) = 0x00;
13418: }
1.1.1.19 root 13419: }
13420: }
13421:
1.1.1.30 root 13422: inline void msdos_call_xms_0fh()
13423: {
13424: msdos_call_xms_0fh(REG16(BX));
13425: }
13426:
1.1.1.19 root 13427: inline void msdos_call_xms_10h()
13428: {
13429: int seg;
13430:
13431: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
13432: REG16(AX) = 0x0001;
13433: REG16(BX) = seg;
13434: } else {
13435: REG16(AX) = 0x0000;
13436: REG8(BL) = 0xb0;
13437: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
13438: }
13439: }
13440:
13441: inline void msdos_call_xms_11h()
13442: {
13443: int mcb_seg = REG16(DX) - 1;
13444: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
13445:
13446: if(mcb->mz == 'M' || mcb->mz == 'Z') {
13447: msdos_mem_free(REG16(DX));
13448: REG16(AX) = 0x0001;
13449: REG8(BL) = 0x00;
13450: } else {
13451: REG16(AX) = 0x0000;
13452: REG8(BL) = 0xb2;
13453: }
13454: }
13455:
13456: inline void msdos_call_xms_12h()
13457: {
13458: int mcb_seg = REG16(DX) - 1;
13459: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
13460: int max_paragraphs;
13461:
13462: if(mcb->mz == 'M' || mcb->mz == 'Z') {
13463: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
13464: REG16(AX) = 0x0001;
13465: REG8(BL) = 0x00;
13466: } else {
13467: REG16(AX) = 0x0000;
13468: REG8(BL) = 0xb0;
13469: REG16(DX) = max_paragraphs;
13470: }
13471: } else {
13472: REG16(AX) = 0x0000;
13473: REG8(BL) = 0xb2;
13474: }
13475: }
13476:
1.1.1.29 root 13477: #if defined(HAS_I386)
13478:
13479: inline void msdos_call_xms_88h()
13480: {
13481: REG32(EAX) = REG32(EDX) = 0x0000;
13482:
1.1.1.30 root 13483: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13484: if(emb_handle->handle == 0) {
13485: if(REG32(EAX) < emb_handle->size_kb) {
13486: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 13487: }
1.1.1.30 root 13488: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 13489: }
13490: }
13491:
13492: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
13493: REG8(BL) = 0xa0;
13494: } else {
13495: REG8(BL) = 0x00;
13496: }
13497: REG32(ECX) = EMB_END - 1;
13498: }
13499:
13500: inline void msdos_call_xms_89h()
13501: {
1.1.1.30 root 13502: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 13503: }
13504:
13505: inline void msdos_call_xms_8eh()
13506: {
1.1.1.30 root 13507: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13508:
13509: if(emb_handle == NULL) {
1.1.1.29 root 13510: REG16(AX) = 0x0000;
13511: REG8(BL) = 0xa2;
13512: } else {
13513: REG16(AX) = 0x0001;
1.1.1.30 root 13514: REG8(BH) = emb_handle->lock;
13515: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
13516: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 13517: }
13518: }
13519:
13520: inline void msdos_call_xms_8fh()
13521: {
1.1.1.30 root 13522: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 13523: }
13524:
13525: #endif
1.1.1.19 root 13526: #endif
13527:
1.1.1.26 root 13528: UINT16 msdos_get_equipment()
13529: {
13530: static UINT16 equip = 0;
13531:
13532: if(equip == 0) {
13533: #ifdef SUPPORT_FPU
13534: equip |= (1 << 1); // 80x87 coprocessor installed
13535: #endif
13536: equip |= (1 << 2); // pointing device installed (PS/2)
13537: equip |= (2 << 4); // initial video mode (80x25 color)
13538: // equip |= (1 << 8); // 0 if DMA installed
13539: equip |= (2 << 9); // number of serial ports
13540: 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 13541:
13542: // check only A: and B: if it is floppy drive
13543: DWORD dwDrives = GetLogicalDrives();
13544: int n = 0;
13545: for(int i = 0; i < 2; i++) {
13546: if(dwDrives & (1 << i)) {
13547: char volume[] = "A:\\";
13548: volume[0] = 'A' + i;
13549: if(GetDriveType(volume) == DRIVE_REMOVABLE) {
13550: n++;
13551: }
13552: }
13553: }
13554: if(n != 0) {
13555: equip |= (1 << 0); // floppy disk(s) installed
13556: n--;
13557: equip |= (n << 6); // number of floppies installed less 1
13558: }
13559: // if(joyGetNumDevs() != 0) {
13560: // equip |= (1 << 12); // game port installed
13561: // }
1.1.1.26 root 13562: }
13563: return(equip);
13564: }
13565:
1.1 root 13566: void msdos_syscall(unsigned num)
13567: {
1.1.1.22 root 13568: #ifdef ENABLE_DEBUG_SYSCALL
13569: if(num == 0x68) {
13570: // dummy interrupt for EMS (int 67h)
1.1.1.33 root 13571: 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 13572: } else if(num == 0x69) {
13573: // dummy interrupt for XMS (call far)
1.1.1.33 root 13574: 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.22 root 13575: } else if(num == 0x6a) {
13576: // dummy interrupt for case map routine pointed in the country info
13577: } else {
1.1.1.33 root 13578: 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 13579: }
13580: #endif
1.1.1.33 root 13581: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
1.1.1.22 root 13582:
1.1 root 13583: switch(num) {
13584: case 0x00:
1.1.1.28 root 13585: try {
13586: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13587: error("division by zero\n");
13588: } catch(...) {
13589: fatalerror("division by zero detected, and failed to terminate current process\n");
13590: }
1.1 root 13591: break;
13592: case 0x04:
1.1.1.28 root 13593: try {
13594: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13595: error("overflow\n");
13596: } catch(...) {
13597: fatalerror("overflow detected, and failed to terminate current process\n");
13598: }
1.1 root 13599: break;
13600: case 0x06:
13601: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 13602: if(!ignore_illegal_insn) {
1.1.1.28 root 13603: try {
13604: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13605: error("illegal instruction\n");
13606: } catch(...) {
13607: fatalerror("illegal instruction detected, and failed to terminate current process\n");
13608: }
1.1.1.14 root 13609: } else {
13610: #if defined(HAS_I386)
13611: m_eip++;
13612: #else
13613: m_pc++;
13614: #endif
13615: }
1.1 root 13616: break;
1.1.1.33 root 13617: case 0x09:
13618: // ctrl-break is pressed
13619: if(raise_int_1bh) {
13620: #if defined(HAS_I386)
13621: m_ext = 0; // not an external interrupt
13622: i386_trap(0x1b, 1, 0);
13623: m_ext = 1;
13624: #else
13625: PREFIX86(_interrupt)(0x1b);
13626: #endif
13627: raise_int_1bh = false;
13628: }
1.1.1.8 root 13629: case 0x08:
1.1.1.14 root 13630: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 13631: case 0x0b:
13632: case 0x0c:
13633: case 0x0d:
13634: case 0x0e:
13635: case 0x0f:
13636: // EOI
13637: pic[0].isr &= ~(1 << (num - 0x08));
13638: pic_update();
13639: break;
1.1 root 13640: case 0x10:
13641: // PC BIOS - Video
1.1.1.14 root 13642: if(!restore_console_on_exit) {
1.1.1.15 root 13643: change_console_size(scr_width, scr_height);
1.1 root 13644: }
1.1.1.3 root 13645: m_CF = 0;
1.1 root 13646: switch(REG8(AH)) {
1.1.1.16 root 13647: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 13648: case 0x01: pcbios_int_10h_01h(); break;
13649: case 0x02: pcbios_int_10h_02h(); break;
13650: case 0x03: pcbios_int_10h_03h(); break;
13651: case 0x05: pcbios_int_10h_05h(); break;
13652: case 0x06: pcbios_int_10h_06h(); break;
13653: case 0x07: pcbios_int_10h_07h(); break;
13654: case 0x08: pcbios_int_10h_08h(); break;
13655: case 0x09: pcbios_int_10h_09h(); break;
13656: case 0x0a: pcbios_int_10h_0ah(); break;
13657: case 0x0b: break;
13658: case 0x0c: break;
13659: case 0x0d: break;
13660: case 0x0e: pcbios_int_10h_0eh(); break;
13661: case 0x0f: pcbios_int_10h_0fh(); break;
13662: case 0x10: break;
1.1.1.14 root 13663: case 0x11: pcbios_int_10h_11h(); break;
13664: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 13665: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 13666: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 13667: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 13668: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
13669: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 13670: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 13671: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
13672: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 13673: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 13674: case 0x6f: break;
1.1.1.22 root 13675: case 0x80: m_CF = 1; break; // unknown
13676: case 0x81: m_CF = 1; break; // unknown
1.1 root 13677: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 13678: case 0x83: pcbios_int_10h_83h(); break;
13679: case 0x8b: break;
13680: case 0x8c: m_CF = 1; break; // unknown
13681: case 0x8d: m_CF = 1; break; // unknown
13682: case 0x8e: m_CF = 1; break; // unknown
13683: case 0x90: pcbios_int_10h_90h(); break;
13684: case 0x91: pcbios_int_10h_91h(); break;
13685: case 0x92: break;
13686: case 0x93: break;
13687: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 13688: case 0xfa: break; // ega register interface library is not installed
1.1 root 13689: case 0xfe: pcbios_int_10h_feh(); break;
13690: case 0xff: pcbios_int_10h_ffh(); break;
13691: default:
1.1.1.22 root 13692: 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));
13693: m_CF = 1;
1.1 root 13694: break;
13695: }
13696: break;
13697: case 0x11:
13698: // PC BIOS - Get Equipment List
1.1.1.26 root 13699: REG16(AX) = msdos_get_equipment();
1.1 root 13700: break;
13701: case 0x12:
13702: // PC BIOS - Get Memory Size
1.1.1.33 root 13703: REG16(AX) = *(UINT16 *)(mem + 0x413);
1.1 root 13704: break;
13705: case 0x13:
13706: // PC BIOS - Disk
1.1.1.22 root 13707: // 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 13708: REG8(AH) = 0xff;
1.1.1.3 root 13709: m_CF = 1;
1.1 root 13710: break;
13711: case 0x14:
13712: // PC BIOS - Serial I/O
1.1.1.25 root 13713: switch(REG8(AH)) {
13714: case 0x00: pcbios_int_14h_00h(); break;
13715: case 0x01: pcbios_int_14h_01h(); break;
13716: case 0x02: pcbios_int_14h_02h(); break;
13717: case 0x03: pcbios_int_14h_03h(); break;
13718: case 0x04: pcbios_int_14h_04h(); break;
13719: case 0x05: pcbios_int_14h_05h(); break;
13720: default:
13721: 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));
13722: break;
13723: }
1.1 root 13724: break;
13725: case 0x15:
13726: // PC BIOS
1.1.1.3 root 13727: m_CF = 0;
1.1 root 13728: switch(REG8(AH)) {
1.1.1.14 root 13729: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 13730: case 0x23: pcbios_int_15h_23h(); break;
13731: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 13732: case 0x41: break;
1.1 root 13733: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 13734: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 13735: case 0x53: pcbios_int_15h_53h(); break;
1.1 root 13736: case 0x86: pcbios_int_15h_86h(); break;
13737: case 0x87: pcbios_int_15h_87h(); break;
13738: case 0x88: pcbios_int_15h_88h(); break;
13739: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 13740: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 13741: case 0xc0: // PS/2 ???
13742: case 0xc1:
13743: case 0xc2:
1.1.1.30 root 13744: case 0xc3: // PS50+ ???
13745: case 0xc4:
1.1.1.22 root 13746: REG8(AH) = 0x86;
13747: m_CF = 1;
13748: break;
1.1.1.3 root 13749: #if defined(HAS_I386)
1.1 root 13750: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 13751: #endif
1.1 root 13752: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 13753: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 13754: default:
1.1.1.22 root 13755: 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));
13756: REG8(AH) = 0x86;
1.1.1.3 root 13757: m_CF = 1;
1.1 root 13758: break;
13759: }
13760: break;
13761: case 0x16:
13762: // PC BIOS - Keyboard
1.1.1.3 root 13763: m_CF = 0;
1.1 root 13764: switch(REG8(AH)) {
13765: case 0x00: pcbios_int_16h_00h(); break;
13766: case 0x01: pcbios_int_16h_01h(); break;
13767: case 0x02: pcbios_int_16h_02h(); break;
13768: case 0x03: pcbios_int_16h_03h(); break;
13769: case 0x05: pcbios_int_16h_05h(); break;
13770: case 0x10: pcbios_int_16h_00h(); break;
13771: case 0x11: pcbios_int_16h_01h(); break;
13772: case 0x12: pcbios_int_16h_12h(); break;
13773: case 0x13: pcbios_int_16h_13h(); break;
13774: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 13775: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 13776: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 13777: case 0xda: break; // unknown
13778: case 0xff: break; // unknown
1.1 root 13779: default:
1.1.1.22 root 13780: 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 13781: break;
13782: }
13783: break;
13784: case 0x17:
13785: // PC BIOS - Printer
1.1.1.22 root 13786: // 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 13787: break;
13788: case 0x1a:
13789: // PC BIOS - Timer
1.1.1.3 root 13790: m_CF = 0;
1.1 root 13791: switch(REG8(AH)) {
13792: case 0x00: pcbios_int_1ah_00h(); break;
13793: case 0x01: break;
13794: case 0x02: pcbios_int_1ah_02h(); break;
13795: case 0x03: break;
13796: case 0x04: pcbios_int_1ah_04h(); break;
13797: case 0x05: break;
13798: case 0x0a: pcbios_int_1ah_0ah(); break;
13799: case 0x0b: break;
1.1.1.14 root 13800: case 0x35: break; // Word Perfect Third Party Interface?
13801: case 0x36: break; // Word Perfect Third Party Interface
13802: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 13803: default:
1.1.1.22 root 13804: 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 13805: break;
13806: }
13807: break;
1.1.1.33 root 13808: case 0x1b:
13809: mem[0x471] = 0x00;
13810: break;
1.1 root 13811: case 0x20:
1.1.1.28 root 13812: try {
13813: msdos_process_terminate(SREG(CS), retval, 1);
13814: } catch(...) {
13815: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
13816: }
1.1 root 13817: break;
13818: case 0x21:
13819: // MS-DOS System Call
1.1.1.3 root 13820: m_CF = 0;
1.1.1.28 root 13821: try {
13822: switch(REG8(AH)) {
13823: case 0x00: msdos_int_21h_00h(); break;
13824: case 0x01: msdos_int_21h_01h(); break;
13825: case 0x02: msdos_int_21h_02h(); break;
13826: case 0x03: msdos_int_21h_03h(); break;
13827: case 0x04: msdos_int_21h_04h(); break;
13828: case 0x05: msdos_int_21h_05h(); break;
13829: case 0x06: msdos_int_21h_06h(); break;
13830: case 0x07: msdos_int_21h_07h(); break;
13831: case 0x08: msdos_int_21h_08h(); break;
13832: case 0x09: msdos_int_21h_09h(); break;
13833: case 0x0a: msdos_int_21h_0ah(); break;
13834: case 0x0b: msdos_int_21h_0bh(); break;
13835: case 0x0c: msdos_int_21h_0ch(); break;
13836: case 0x0d: msdos_int_21h_0dh(); break;
13837: case 0x0e: msdos_int_21h_0eh(); break;
13838: case 0x0f: msdos_int_21h_0fh(); break;
13839: case 0x10: msdos_int_21h_10h(); break;
13840: case 0x11: msdos_int_21h_11h(); break;
13841: case 0x12: msdos_int_21h_12h(); break;
13842: case 0x13: msdos_int_21h_13h(); break;
13843: case 0x14: msdos_int_21h_14h(); break;
13844: case 0x15: msdos_int_21h_15h(); break;
13845: case 0x16: msdos_int_21h_16h(); break;
13846: case 0x17: msdos_int_21h_17h(); break;
13847: case 0x18: msdos_int_21h_18h(); break;
13848: case 0x19: msdos_int_21h_19h(); break;
13849: case 0x1a: msdos_int_21h_1ah(); break;
13850: case 0x1b: msdos_int_21h_1bh(); break;
13851: case 0x1c: msdos_int_21h_1ch(); break;
13852: case 0x1d: msdos_int_21h_1dh(); break;
13853: case 0x1e: msdos_int_21h_1eh(); break;
13854: case 0x1f: msdos_int_21h_1fh(); break;
13855: case 0x20: msdos_int_21h_20h(); break;
13856: case 0x21: msdos_int_21h_21h(); break;
13857: case 0x22: msdos_int_21h_22h(); break;
13858: case 0x23: msdos_int_21h_23h(); break;
13859: case 0x24: msdos_int_21h_24h(); break;
13860: case 0x25: msdos_int_21h_25h(); break;
13861: case 0x26: msdos_int_21h_26h(); break;
13862: case 0x27: msdos_int_21h_27h(); break;
13863: case 0x28: msdos_int_21h_28h(); break;
13864: case 0x29: msdos_int_21h_29h(); break;
13865: case 0x2a: msdos_int_21h_2ah(); break;
13866: case 0x2b: msdos_int_21h_2bh(); break;
13867: case 0x2c: msdos_int_21h_2ch(); break;
13868: case 0x2d: msdos_int_21h_2dh(); break;
13869: case 0x2e: msdos_int_21h_2eh(); break;
13870: case 0x2f: msdos_int_21h_2fh(); break;
13871: case 0x30: msdos_int_21h_30h(); break;
13872: case 0x31: msdos_int_21h_31h(); break;
13873: case 0x32: msdos_int_21h_32h(); break;
13874: case 0x33: msdos_int_21h_33h(); break;
13875: case 0x34: msdos_int_21h_34h(); break;
13876: case 0x35: msdos_int_21h_35h(); break;
13877: case 0x36: msdos_int_21h_36h(); break;
13878: case 0x37: msdos_int_21h_37h(); break;
13879: case 0x38: msdos_int_21h_38h(); break;
13880: case 0x39: msdos_int_21h_39h(0); break;
13881: case 0x3a: msdos_int_21h_3ah(0); break;
13882: case 0x3b: msdos_int_21h_3bh(0); break;
13883: case 0x3c: msdos_int_21h_3ch(); break;
13884: case 0x3d: msdos_int_21h_3dh(); break;
13885: case 0x3e: msdos_int_21h_3eh(); break;
13886: case 0x3f: msdos_int_21h_3fh(); break;
13887: case 0x40: msdos_int_21h_40h(); break;
13888: case 0x41: msdos_int_21h_41h(0); break;
13889: case 0x42: msdos_int_21h_42h(); break;
13890: case 0x43: msdos_int_21h_43h(0); break;
13891: case 0x44: msdos_int_21h_44h(); break;
13892: case 0x45: msdos_int_21h_45h(); break;
13893: case 0x46: msdos_int_21h_46h(); break;
13894: case 0x47: msdos_int_21h_47h(0); break;
13895: case 0x48: msdos_int_21h_48h(); break;
13896: case 0x49: msdos_int_21h_49h(); break;
13897: case 0x4a: msdos_int_21h_4ah(); break;
13898: case 0x4b: msdos_int_21h_4bh(); break;
13899: case 0x4c: msdos_int_21h_4ch(); break;
13900: case 0x4d: msdos_int_21h_4dh(); break;
13901: case 0x4e: msdos_int_21h_4eh(); break;
13902: case 0x4f: msdos_int_21h_4fh(); break;
13903: case 0x50: msdos_int_21h_50h(); break;
13904: case 0x51: msdos_int_21h_51h(); break;
13905: case 0x52: msdos_int_21h_52h(); break;
1.1.1.33 root 13906: // 0x53: Translate BIOS Parameter Block to Drive Param Bock
1.1.1.28 root 13907: case 0x54: msdos_int_21h_54h(); break;
13908: case 0x55: msdos_int_21h_55h(); break;
13909: case 0x56: msdos_int_21h_56h(0); break;
13910: case 0x57: msdos_int_21h_57h(); break;
13911: case 0x58: msdos_int_21h_58h(); break;
13912: case 0x59: msdos_int_21h_59h(); break;
13913: case 0x5a: msdos_int_21h_5ah(); break;
13914: case 0x5b: msdos_int_21h_5bh(); break;
13915: case 0x5c: msdos_int_21h_5ch(); break;
13916: case 0x5d: msdos_int_21h_5dh(); break;
1.1.1.33 root 13917: // 0x5e: MS-Network
1.1.1.30 root 13918: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 13919: case 0x60: msdos_int_21h_60h(0); break;
13920: case 0x61: msdos_int_21h_61h(); break;
13921: case 0x62: msdos_int_21h_62h(); break;
13922: case 0x63: msdos_int_21h_63h(); break;
1.1.1.33 root 13923: // 0x64: Set Device Driver Lockahead Flag
1.1.1.28 root 13924: case 0x65: msdos_int_21h_65h(); break;
13925: case 0x66: msdos_int_21h_66h(); break;
13926: case 0x67: msdos_int_21h_67h(); break;
13927: case 0x68: msdos_int_21h_68h(); break;
13928: case 0x69: msdos_int_21h_69h(); break;
13929: case 0x6a: msdos_int_21h_6ah(); break;
13930: case 0x6b: msdos_int_21h_6bh(); break;
13931: case 0x6c: msdos_int_21h_6ch(0); break;
1.1.1.33 root 13932: // 0x6d: Find First ROM Program
13933: // 0x6e: Find Next ROM Program
13934: // 0x6f: Get/Set ROM Scan Start Address
13935: // 0x70: Windows95 - Get/Set Internationalization Information
1.1.1.28 root 13936: case 0x71:
1.1.1.33 root 13937: // Windows95 - Long Filename Functions
1.1.1.28 root 13938: switch(REG8(AL)) {
13939: case 0x0d: msdos_int_21h_710dh(); break;
13940: case 0x39: msdos_int_21h_39h(1); break;
13941: case 0x3a: msdos_int_21h_3ah(1); break;
13942: case 0x3b: msdos_int_21h_3bh(1); break;
13943: case 0x41: msdos_int_21h_7141h(1); break;
13944: case 0x43: msdos_int_21h_43h(1); break;
13945: case 0x47: msdos_int_21h_47h(1); break;
13946: case 0x4e: msdos_int_21h_714eh(); break;
13947: case 0x4f: msdos_int_21h_714fh(); break;
13948: case 0x56: msdos_int_21h_56h(1); break;
13949: case 0x60: msdos_int_21h_60h(1); break;
13950: case 0x6c: msdos_int_21h_6ch(1); break;
13951: case 0xa0: msdos_int_21h_71a0h(); break;
13952: case 0xa1: msdos_int_21h_71a1h(); break;
13953: case 0xa6: msdos_int_21h_71a6h(); break;
13954: case 0xa7: msdos_int_21h_71a7h(); break;
13955: case 0xa8: msdos_int_21h_71a8h(); break;
1.1.1.33 root 13956: // 0xa9: Server Create/Open File
1.1.1.28 root 13957: case 0xaa: msdos_int_21h_71aah(); break;
13958: default:
13959: 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));
13960: REG16(AX) = 0x7100;
13961: m_CF = 1;
13962: break;
13963: }
13964: break;
13965: // 0x72: Windows95 beta - LFN FindClose
13966: case 0x73:
1.1.1.33 root 13967: // Windows95 - FAT32 Functions
1.1.1.28 root 13968: switch(REG8(AL)) {
13969: case 0x00: msdos_int_21h_7300h(); break;
1.1.1.33 root 13970: // 0x01: Set Drive Locking ???
1.1.1.28 root 13971: case 0x02: msdos_int_21h_7302h(); break;
13972: case 0x03: msdos_int_21h_7303h(); break;
1.1.1.33 root 13973: // 0x04: Set DPB to Use for Formatting
13974: // 0x05: Extended Absolute Disk Read/Write
1.1.1.28 root 13975: default:
13976: 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));
13977: REG16(AX) = 0x7300;
13978: m_CF = 1;
13979: break;
13980: }
1.1 root 13981: break;
1.1.1.30 root 13982: case 0xdb: msdos_int_21h_dbh(); break;
13983: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 13984: default:
1.1.1.22 root 13985: 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 13986: REG16(AX) = 0x01;
1.1.1.3 root 13987: m_CF = 1;
1.1 root 13988: break;
13989: }
1.1.1.28 root 13990: } catch(int error) {
13991: REG16(AX) = error;
13992: m_CF = 1;
13993: } catch(...) {
13994: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 13995: m_CF = 1;
1.1 root 13996: }
1.1.1.3 root 13997: if(m_CF) {
1.1.1.23 root 13998: sda_t *sda = (sda_t *)(mem + SDA_TOP);
13999: sda->extended_error_code = REG16(AX);
14000: switch(sda->extended_error_code) {
14001: case 4: // Too many open files
14002: case 8: // Insufficient memory
14003: sda->error_class = 1; // Out of resource
14004: break;
14005: case 5: // Access denied
14006: sda->error_class = 3; // Authorization
14007: break;
14008: case 7: // Memory control block destroyed
14009: sda->error_class = 4; // Internal
14010: break;
14011: case 2: // File not found
14012: case 3: // Path not found
14013: case 15: // Invaid drive specified
14014: case 18: // No more files
14015: sda->error_class = 8; // Not found
14016: break;
14017: case 32: // Sharing violation
14018: case 33: // Lock violation
14019: sda->error_class = 10; // Locked
14020: break;
14021: // case 16: // Removal of current directory attempted
14022: case 19: // Attempted write on protected disk
14023: case 21: // Drive not ready
14024: // case 29: // Write failure
14025: // case 30: // Read failure
14026: // case 82: // Cannot create subdirectory
14027: sda->error_class = 11; // Media
14028: break;
14029: case 80: // File already exists
14030: sda->error_class = 12; // Already exist
14031: break;
14032: default:
14033: sda->error_class = 13; // Unknown
14034: break;
14035: }
14036: sda->suggested_action = 1; // Retry
14037: sda->locus_of_last_error = 1; // Unknown
1.1 root 14038: }
1.1.1.33 root 14039: if(ctrl_break_checking && ctrl_break_detected) {
1.1.1.26 root 14040: // raise int 23h
14041: #if defined(HAS_I386)
14042: m_ext = 0; // not an external interrupt
14043: i386_trap(0x23, 1, 0);
14044: m_ext = 1;
14045: #else
14046: PREFIX86(_interrupt)(0x23);
14047: #endif
14048: }
1.1 root 14049: break;
14050: case 0x22:
14051: fatalerror("int 22h (terminate address)\n");
14052: case 0x23:
1.1.1.28 root 14053: try {
14054: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
14055: } catch(...) {
14056: fatalerror("failed to terminate the current process by int 23h\n");
14057: }
1.1 root 14058: break;
14059: case 0x24:
1.1.1.32 root 14060: /*
1.1.1.28 root 14061: try {
14062: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
14063: } catch(...) {
14064: fatalerror("failed to terminate the current process by int 24h\n");
14065: }
1.1.1.32 root 14066: */
14067: msdos_int_24h();
1.1 root 14068: break;
14069: case 0x25:
14070: msdos_int_25h();
14071: break;
14072: case 0x26:
14073: msdos_int_26h();
14074: break;
14075: case 0x27:
1.1.1.28 root 14076: try {
14077: msdos_int_27h();
14078: } catch(...) {
14079: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
14080: }
1.1 root 14081: break;
14082: case 0x28:
14083: Sleep(10);
1.1.1.35! root 14084: REQUEST_HARDWRE_UPDATE();
1.1 root 14085: break;
14086: case 0x29:
14087: msdos_int_29h();
14088: break;
14089: case 0x2e:
14090: msdos_int_2eh();
14091: break;
14092: case 0x2f:
14093: // multiplex interrupt
14094: switch(REG8(AH)) {
1.1.1.22 root 14095: case 0x05: msdos_int_2fh_05h(); break;
14096: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 14097: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 14098: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 14099: case 0x14: msdos_int_2fh_14h(); break;
14100: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 14101: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 14102: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 14103: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 14104: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 14105: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 14106: case 0x46: msdos_int_2fh_46h(); break;
14107: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 14108: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 14109: case 0x4b: msdos_int_2fh_4bh(); break;
1.1 root 14110: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 14111: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.24 root 14112: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 14113: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.34 root 14114: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.30 root 14115: // Installation Check
14116: case 0x01: // PRINT.COM
14117: case 0x02: // PC LAN Program Redirector
14118: case 0x06: // ASSIGN
14119: case 0x08: // DRIVER.SYS
14120: case 0x10: // SHARE
14121: case 0x17: // Clibboard functions
14122: case 0x1b: // XMA2EMS.SYS
14123: case 0x23: // DR DOS 5.0 GRAFTABL
14124: case 0x27: // DR-DOR 6.0 TaskMAX
14125: case 0x2e: // Novell DOS 7 GRAFTABL
1.1.1.33 root 14126: case 0x39: // Kingswood TSR INTERFACE
14127: case 0x41: // DOS Enhanced LAN Manager 2.0+ MINIPOP/NETPOPUP
1.1.1.30 root 14128: case 0x45: // PROF.COM
14129: case 0x51: // ODIHELP.EXE
1.1.1.33 root 14130: case 0x52: // JAM.SYS v1.10+
1.1.1.30 root 14131: case 0x54: // POWER.EXE
14132: case 0x56: // INTERLNK
1.1.1.33 root 14133: case 0x57: // IOMEGA DRIVERS
1.1.1.30 root 14134: case 0x70: // License Service API
1.1.1.33 root 14135: case 0x72: // SRDISK v1.30+
1.1.1.30 root 14136: case 0x7a: // Novell NetWare
1.1.1.33 root 14137: case 0x7f: // PRINDIR v9.0
14138: case 0x80: // FAX BIOS
14139: case 0x81: // Nanosoft, Inc. TurboNET redirector
14140: case 0x82: // Nanosoft, Inc. CAPDOS
14141: case 0x89: // WHOA!.COM
14142: case 0x90: // Resident AID
1.1.1.30 root 14143: case 0x94: // MICRO.EXE
1.1.1.33 root 14144: case 0x97: // Micro Focus COBOL v3.1.31
14145: case 0x98: // Micro Focus COBOL v3.1.31
14146: case 0x99: // DOS Navigator II
14147: case 0x9e: // INTMON v2.1
14148: case 0x9f: // INTCFG v2.1
14149: case 0xa9: // METZTSR.COM
14150: case 0xab: // SRSoft MODAL PC v2
1.1.1.30 root 14151: case 0xac: // GRAPHICS.COM
1.1.1.33 root 14152: case 0xaf: // WinDOS v2.11
1.1.1.30 root 14153: case 0xb0: // GRAFTABLE.COM
1.1.1.33 root 14154: case 0xb4: // IBM PC3270 EMULATION PROG v3
1.1.1.30 root 14155: case 0xb8: // NETWORK
14156: case 0xb9: // RECEIVER.COM
14157: case 0xbc: // EGA.SYS
1.1.1.33 root 14158: case 0xbe: // REDVIEW
1.1.1.30 root 14159: case 0xbf: // PC LAN Program - REDIRIFS.EXE
14160: case 0xc0: // Novell LSL.COM
1.1.1.33 root 14161: case 0xc1: // Personal NetWare - STPIPX v1.00
14162: case 0xc3: // SETWPR.COM
14163: case 0xc5: // PC-DOS Econet v1.05
14164: case 0xc7: // COLAP.COM
14165: case 0xc9: // ThunderByte???
14166: case 0xca: // TBSCANX
14167: case 0xcb: // Communicating Applications Specification
14168: case 0xcc: // Tsoft NFSDRVR
14169: case 0xcd: // SWELL.EXE
14170: case 0xcf: // TEMPLEXX 1.0
14171: case 0xd0: // Lotus CD/Networker
1.1.1.30 root 14172: case 0xd2: // PCL-838.EXE
1.1.1.33 root 14173: case 0xd3: // TeleReplica
14174: case 0xd6: // VEDIT VSWAP
14175: case 0xd7: // Banyan VINES v4+
1.1.1.30 root 14176: case 0xd8: // Novell NetWare Lite - CLIENT.EXE
1.1.1.33 root 14177: case 0xda: // ZyXEL ZFAX v1.x
14178: case 0xdb: // ZyXEL ZFAX v2+
14179: case 0xdc: // GOLD.COM
14180: case 0xdd: // MIXFIX.EXE
14181: case 0xde: // Novell Netware - RPRINTER, NPRINTER
14182: case 0xdf: // HyperWare programs
14183: case 0xe0: // SETDRVER.COM v2.10+
14184: case 0xe1: // Phantom2 v1.1+
14185: case 0xe3: // ANARKEY.COM
14186: case 0xed: // Phar Lap DOS EXTENDERS
14187: case 0xee: // XVIEW
14188: case 0xf0: // 4MAP
14189: case 0xf1: // DOS EXTENDER
14190: case 0xf2: // WINX
14191: case 0xf4: // FINDIRQ.COM
14192: case 0xf7: // AUTOPARK.COM
14193: case 0xf8: // SuperStor PRO 2XON.COM
14194: case 0xfb: // AutoBraille v1.1A
14195: case 0xfe: // PC-NFS ???
14196: case 0xff: // Topware Network Operating System
1.1.1.30 root 14197: switch(REG8(AL)) {
14198: case 0x00:
14199: // This is not installed
14200: // REG8(AL) = 0x00;
14201: break;
1.1.1.33 root 14202: case 0x01:
14203: // Banyan VINES v4+ is not installed
14204: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
14205: break;
14206: }
1.1.1.30 root 14207: default:
14208: 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));
14209: REG16(AX) = 0x01;
14210: m_CF = 1;
14211: break;
14212: }
14213: break;
1.1.1.22 root 14214: default:
14215: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
14216: break;
1.1 root 14217: }
14218: break;
1.1.1.24 root 14219: case 0x33:
14220: switch(REG8(AH)) {
14221: case 0x00:
14222: // Mouse
14223: switch(REG8(AL)) {
14224: case 0x00: msdos_int_33h_0000h(); break;
14225: case 0x01: msdos_int_33h_0001h(); break;
14226: case 0x02: msdos_int_33h_0002h(); break;
14227: case 0x03: msdos_int_33h_0003h(); break;
1.1.1.34 root 14228: case 0x04: msdos_int_33h_0004h(); break;
1.1.1.24 root 14229: case 0x05: msdos_int_33h_0005h(); break;
14230: case 0x06: msdos_int_33h_0006h(); break;
14231: case 0x07: msdos_int_33h_0007h(); break;
14232: case 0x08: msdos_int_33h_0008h(); break;
14233: case 0x09: msdos_int_33h_0009h(); break;
1.1.1.34 root 14234: case 0x0a: break; // Define Text Cursor
1.1.1.24 root 14235: case 0x0b: msdos_int_33h_000bh(); break;
14236: case 0x0c: msdos_int_33h_000ch(); break;
1.1.1.34 root 14237: case 0x0d: break; // Light Pen Emulation On
14238: case 0x0e: break; // Light Pen Emulation Off
1.1.1.24 root 14239: case 0x0f: msdos_int_33h_000fh(); break;
1.1.1.34 root 14240: case 0x10: break; // Define Screen Region for Updating
1.1.1.24 root 14241: case 0x11: msdos_int_33h_0011h(); break;
1.1.1.34 root 14242: case 0x12: REG16(AX) = 0xffff; break; // Set Large Graphics Cursor Block
14243: case 0x13: break; // Define Double-Speed Threshold
1.1.1.24 root 14244: case 0x14: msdos_int_33h_0014h(); break;
14245: case 0x15: msdos_int_33h_0015h(); break;
14246: case 0x16: msdos_int_33h_0016h(); break;
14247: case 0x17: msdos_int_33h_0017h(); break;
14248: case 0x1a: msdos_int_33h_001ah(); break;
14249: case 0x1b: msdos_int_33h_001bh(); break;
14250: case 0x1d: msdos_int_33h_001dh(); break;
14251: case 0x1e: msdos_int_33h_001eh(); break;
1.1.1.34 root 14252: case 0x1f: msdos_int_33h_001fh(); break;
14253: case 0x20: msdos_int_33h_0020h(); break;
1.1.1.24 root 14254: case 0x21: msdos_int_33h_0021h(); break;
14255: case 0x22: msdos_int_33h_0022h(); break;
14256: case 0x23: msdos_int_33h_0023h(); break;
14257: case 0x24: msdos_int_33h_0024h(); break;
14258: case 0x26: msdos_int_33h_0026h(); break;
14259: case 0x2a: msdos_int_33h_002ah(); break;
1.1.1.34 root 14260: case 0x2f: break; // Mouse Hardware Reset
1.1.1.24 root 14261: case 0x31: msdos_int_33h_0031h(); break;
14262: case 0x32: msdos_int_33h_0032h(); break;
14263: default:
14264: 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));
14265: break;
14266: }
14267: break;
14268: default:
14269: 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));
14270: break;
14271: }
14272: break;
1.1.1.19 root 14273: case 0x68:
14274: // dummy interrupt for EMS (int 67h)
14275: switch(REG8(AH)) {
14276: case 0x40: msdos_int_67h_40h(); break;
14277: case 0x41: msdos_int_67h_41h(); break;
14278: case 0x42: msdos_int_67h_42h(); break;
14279: case 0x43: msdos_int_67h_43h(); break;
14280: case 0x44: msdos_int_67h_44h(); break;
14281: case 0x45: msdos_int_67h_45h(); break;
14282: case 0x46: msdos_int_67h_46h(); break;
14283: case 0x47: msdos_int_67h_47h(); break;
14284: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 14285: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
14286: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 14287: case 0x4b: msdos_int_67h_4bh(); break;
14288: case 0x4c: msdos_int_67h_4ch(); break;
14289: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 14290: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 14291: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 14292: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 14293: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 14294: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 14295: case 0x53: msdos_int_67h_53h(); break;
14296: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 14297: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
14298: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
14299: case 0x57: msdos_int_67h_57h(); break;
14300: case 0x58: msdos_int_67h_58h(); break;
14301: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
14302: case 0x5a: msdos_int_67h_5ah(); break;
14303: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
14304: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
14305: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.31 root 14306: // 0x60: EEMS - Get Physical Window Array
14307: // 0x61: EEMS - Generic Accelerator Card Support
14308: // 0x68: EEMS - Get Address of All Pge Frames om System
14309: // 0x69: EEMS - Map Page into Frame
14310: // 0x6a: EEMS - Page Mapping
14311: // 0xde: VCPI
1.1.1.30 root 14312: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 14313: default:
1.1.1.22 root 14314: 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 14315: REG8(AH) = 0x84;
14316: break;
14317: }
14318: break;
14319: #ifdef SUPPORT_XMS
14320: case 0x69:
14321: // dummy interrupt for XMS (call far)
1.1.1.28 root 14322: try {
14323: switch(REG8(AH)) {
14324: case 0x00: msdos_call_xms_00h(); break;
14325: case 0x01: msdos_call_xms_01h(); break;
14326: case 0x02: msdos_call_xms_02h(); break;
14327: case 0x03: msdos_call_xms_03h(); break;
14328: case 0x04: msdos_call_xms_04h(); break;
14329: case 0x05: msdos_call_xms_05h(); break;
14330: case 0x06: msdos_call_xms_06h(); break;
14331: case 0x07: msdos_call_xms_07h(); break;
14332: case 0x08: msdos_call_xms_08h(); break;
14333: case 0x09: msdos_call_xms_09h(); break;
14334: case 0x0a: msdos_call_xms_0ah(); break;
14335: case 0x0b: msdos_call_xms_0bh(); break;
14336: case 0x0c: msdos_call_xms_0ch(); break;
14337: case 0x0d: msdos_call_xms_0dh(); break;
14338: case 0x0e: msdos_call_xms_0eh(); break;
14339: case 0x0f: msdos_call_xms_0fh(); break;
14340: case 0x10: msdos_call_xms_10h(); break;
14341: case 0x11: msdos_call_xms_11h(); break;
14342: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 14343: #if defined(HAS_I386)
14344: case 0x88: msdos_call_xms_88h(); break;
14345: case 0x89: msdos_call_xms_89h(); break;
14346: case 0x8e: msdos_call_xms_8eh(); break;
14347: case 0x8f: msdos_call_xms_8fh(); break;
14348: #endif
1.1.1.28 root 14349: default:
14350: 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));
14351: REG16(AX) = 0x0000;
14352: REG8(BL) = 0x80; // function not implemented
14353: break;
14354: }
14355: } catch(...) {
1.1.1.19 root 14356: REG16(AX) = 0x0000;
1.1.1.28 root 14357: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 14358: }
14359: break;
14360: #endif
14361: case 0x6a:
1.1.1.24 root 14362: // irq12 (mouse)
14363: mouse_push_ax = REG16(AX);
14364: mouse_push_bx = REG16(BX);
14365: mouse_push_cx = REG16(CX);
14366: mouse_push_dx = REG16(DX);
14367: mouse_push_si = REG16(SI);
14368: mouse_push_di = REG16(DI);
14369:
1.1.1.34 root 14370: if(/*mouse.hidden == 0 && */mouse.call_addr.dw != 0) {
1.1.1.24 root 14371: REG16(AX) = mouse.status_irq;
14372: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 14373: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
14374: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
1.1.1.24 root 14375: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
14376: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
14377:
14378: mem[0xfffd0 + 0x02] = 0x9a; // call far
14379: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
14380: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
14381: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
14382: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
14383: } else {
14384: mem[0xfffd0 + 0x02] = 0x90; // nop
14385: mem[0xfffd0 + 0x03] = 0x90; // nop
14386: mem[0xfffd0 + 0x04] = 0x90; // nop
14387: mem[0xfffd0 + 0x05] = 0x90; // nop
14388: mem[0xfffd0 + 0x06] = 0x90; // nop
14389: }
14390: break;
14391: case 0x6b:
14392: // end of irq12 (mouse)
14393: REG16(AX) = mouse_push_ax;
14394: REG16(BX) = mouse_push_bx;
14395: REG16(CX) = mouse_push_cx;
14396: REG16(DX) = mouse_push_dx;
14397: REG16(SI) = mouse_push_si;
14398: REG16(DI) = mouse_push_di;
14399:
14400: // EOI
14401: if((pic[1].isr &= ~(1 << 4)) == 0) {
14402: pic[0].isr &= ~(1 << 2); // master
14403: }
14404: pic_update();
14405: break;
14406: case 0x6c:
1.1.1.19 root 14407: // dummy interrupt for case map routine pointed in the country info
14408: if(REG8(AL) >= 0x80) {
14409: char tmp[2] = {0};
14410: tmp[0] = REG8(AL);
14411: my_strupr(tmp);
14412: REG8(AL) = tmp[0];
14413: }
14414: break;
1.1.1.27 root 14415: case 0x6d:
14416: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
14417: REG8(AL) = 0x86; // not supported
14418: m_CF = 1;
14419: break;
1.1.1.32 root 14420: case 0x6e:
14421: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
14422: {
14423: UINT16 code = REG16(AX);
14424: if(code & 0xf0) {
14425: code = (code & 7) | ((code & 0x10) >> 1);
14426: }
14427: for(int i = 0; i < array_length(param_error_table); i++) {
14428: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
14429: const char *message = NULL;
14430: if(active_code_page == 932) {
14431: message = param_error_table[i].message_japanese;
14432: }
14433: if(message == NULL) {
14434: message = param_error_table[i].message_english;
14435: }
14436: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
14437: strcpy((char *)(mem + WORK_TOP + 1), message);
14438:
14439: SREG(ES) = WORK_TOP >> 4;
14440: i386_load_segment_descriptor(ES);
14441: REG16(DI) = 0x0000;
14442: break;
14443: }
14444: }
14445: }
14446: break;
1.1.1.8 root 14447: case 0x70:
14448: case 0x71:
14449: case 0x72:
14450: case 0x73:
14451: case 0x74:
14452: case 0x75:
14453: case 0x76:
14454: case 0x77:
14455: // EOI
14456: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
14457: pic[0].isr &= ~(1 << 2); // master
14458: }
14459: pic_update();
14460: break;
1.1 root 14461: default:
1.1.1.22 root 14462: // 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 14463: break;
14464: }
14465:
14466: // update cursor position
14467: if(cursor_moved) {
14468: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23 root 14469: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 14470: if(!restore_console_on_exit) {
14471: scr_top = csbi.srWindow.Top;
14472: }
1.1 root 14473: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 14474: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 14475: cursor_moved = false;
14476: }
14477: }
14478:
14479: // init
14480:
14481: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
14482: {
14483: // init file handler
14484: memset(file_handler, 0, sizeof(file_handler));
14485: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
14486: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
14487: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 14488: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 14489: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 14490: #else
14491: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
14492: #endif
14493: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 14494: }
1.1.1.21 root 14495: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 14496: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 14497: #else
14498: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 14499: #endif
1.1.1.21 root 14500: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
14501: }
1.1 root 14502: _dup2(0, DUP_STDIN);
14503: _dup2(1, DUP_STDOUT);
14504: _dup2(2, DUP_STDERR);
1.1.1.21 root 14505: _dup2(3, DUP_STDAUX);
14506: _dup2(4, DUP_STDPRN);
1.1 root 14507:
1.1.1.24 root 14508: // init mouse
14509: memset(&mouse, 0, sizeof(mouse));
1.1.1.34 root 14510: mouse.enabled = true; // from DOSBox
14511: mouse.hidden = 1; // hidden in default ???
14512: mouse.old_hidden = 1; // from DOSBox
14513: mouse.max_position.x = 8 * (scr_width - 1);
14514: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 14515: mouse.mickey.x = 8;
14516: mouse.mickey.y = 16;
14517:
1.1.1.26 root 14518: #ifdef SUPPORT_XMS
14519: // init xms
14520: msdos_xms_init();
14521: #endif
14522:
1.1 root 14523: // init process
14524: memset(process, 0, sizeof(process));
14525:
1.1.1.13 root 14526: // init dtainfo
14527: msdos_dta_info_init();
14528:
1.1 root 14529: // init memory
14530: memset(mem, 0, sizeof(mem));
14531:
14532: // bios data area
1.1.1.23 root 14533: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 14534: CONSOLE_SCREEN_BUFFER_INFO csbi;
14535: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 14536: CONSOLE_FONT_INFO cfi;
14537: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
14538:
14539: int regen = min(scr_width * scr_height * 2, 0x8000);
14540: text_vram_top_address = TEXT_VRAM_TOP;
14541: text_vram_end_address = text_vram_top_address + regen;
14542: shadow_buffer_top_address = SHADOW_BUF_TOP;
14543: shadow_buffer_end_address = shadow_buffer_top_address + regen;
14544:
14545: if(regen > 0x4000) {
14546: regen = 0x8000;
14547: vram_pages = 1;
14548: } else if(regen > 0x2000) {
14549: regen = 0x4000;
14550: vram_pages = 2;
14551: } else if(regen > 0x1000) {
14552: regen = 0x2000;
14553: vram_pages = 4;
14554: } else {
14555: regen = 0x1000;
14556: vram_pages = 8;
14557: }
1.1 root 14558:
1.1.1.25 root 14559: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
14560: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 14561: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
14562: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 14563: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.26 root 14564: // *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
1.1.1.25 root 14565: // *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32 root 14566: #ifdef EXT_BIOS_TOP
1.1.1.25 root 14567: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32 root 14568: #endif
1.1.1.26 root 14569: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1.1.33 root 14570: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
1.1 root 14571: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 14572: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
14573: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 14574: *(UINT16 *)(mem + 0x44e) = 0;
14575: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 14576: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 14577: *(UINT8 *)(mem + 0x460) = 7;
14578: *(UINT8 *)(mem + 0x461) = 7;
14579: *(UINT8 *)(mem + 0x462) = 0;
14580: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 14581: *(UINT8 *)(mem + 0x465) = 0x09;
14582: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 14583: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
14584: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
14585: *(UINT8 *)(mem + 0x487) = 0x60;
14586: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32 root 14587: #ifdef EXT_BIOS_TOP
1.1.1.25 root 14588: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32 root 14589: #endif
1.1.1.14 root 14590:
14591: // initial screen
14592: SMALL_RECT rect;
14593: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
14594: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
14595: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
14596: for(int x = 0; x < scr_width; x++) {
14597: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
14598: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
14599: }
14600: }
1.1 root 14601:
1.1.1.19 root 14602: // init mcb
1.1 root 14603: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 14604:
14605: // iret table
14606: // note: int 2eh vector should address the routine in command.com,
14607: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
14608: // so move iret table into allocated memory block
14609: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
1.1.1.33 root 14610: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, IRET_SIZE >> 4);
1.1.1.19 root 14611: IRET_TOP = seg << 4;
14612: seg += IRET_SIZE >> 4;
1.1.1.25 root 14613: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 14614:
14615: // dummy xms/ems device
1.1.1.33 root 14616: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
1.1.1.19 root 14617: XMS_TOP = seg << 4;
14618: seg += XMS_SIZE >> 4;
14619:
14620: // environment
1.1.1.33 root 14621: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
1.1 root 14622: int env_seg = seg;
14623: int ofs = 0;
1.1.1.32 root 14624: char env_append[ENV_SIZE] = {0}, append_added = 0;
14625: char comspec_added = 0;
1.1.1.33 root 14626: char lastdrive_added = 0;
1.1.1.32 root 14627: char env_msdos_path[ENV_SIZE] = {0};
14628: char env_path[ENV_SIZE] = {0}, path_added = 0;
1.1.1.33 root 14629: char prompt_added = 0;
1.1.1.32 root 14630: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
1.1.1.33 root 14631: char tz_added = 0;
1.1.1.32 root 14632: char *path, *short_path;
14633:
14634: if((path = getenv("MSDOS_APPEND")) != NULL) {
14635: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14636: strcpy(env_append, short_path);
14637: }
14638: }
14639: if((path = getenv("APPEND")) != NULL) {
14640: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14641: if(env_append[0] != '\0') {
14642: strcat(env_append, ";");
14643: }
14644: strcat(env_append, short_path);
14645: }
14646: }
14647:
14648: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
14649: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14650: strcpy(comspec_path, short_path);
14651: }
14652: }
14653: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
14654: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14655: strcpy(comspec_path, short_path);
14656: }
14657: }
1.1 root 14658:
1.1.1.28 root 14659: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32 root 14660: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14661: strcpy(env_msdos_path, short_path);
14662: strcpy(env_path, short_path);
1.1.1.14 root 14663: }
14664: }
1.1.1.28 root 14665: if((path = getenv("PATH")) != NULL) {
1.1.1.32 root 14666: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14667: if(env_path[0] != '\0') {
14668: strcat(env_path, ";");
14669: }
14670: strcat(env_path, short_path);
1.1.1.9 root 14671: }
14672: }
1.1.1.32 root 14673:
14674: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
14675: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 14676: }
1.1.1.32 root 14677: for(int i = 0; i < 4; i++) {
14678: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
14679: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
14680: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14681: strcpy(env_temp, short_path);
14682: break;
14683: }
14684: }
1.1.1.24 root 14685: }
1.1.1.32 root 14686:
1.1.1.9 root 14687: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 14688: // lower to upper
1.1.1.28 root 14689: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 14690: strcpy(tmp, *p);
14691: for(int i = 0;; i++) {
14692: if(tmp[i] == '=') {
14693: tmp[i] = '\0';
14694: sprintf(name, ";%s;", tmp);
1.1.1.25 root 14695: my_strupr(name);
1.1 root 14696: tmp[i] = '=';
14697: break;
14698: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 14699: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 14700: }
14701: }
1.1.1.33 root 14702: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
14703: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
14704: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 14705: // ignore non standard environments
14706: } else {
1.1.1.33 root 14707: if(strncmp(tmp, "APPEND=", 7) == 0) {
1.1.1.32 root 14708: if(env_append[0] != '\0') {
14709: sprintf(tmp, "APPEND=%s", env_append);
14710: } else {
14711: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
14712: }
14713: append_added = 1;
14714: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 14715: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32 root 14716: comspec_added = 1;
1.1.1.33 root 14717: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
14718: char *env = getenv("MSDOS_LASTDRIVE");
14719: if(env != NULL) {
14720: sprintf(tmp, "LASTDRIVE=%s", env);
14721: }
14722: lastdrive_added = 1;
14723: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
1.1.1.28 root 14724: if(env_msdos_path[0] != '\0') {
14725: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
14726: } else {
14727: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
14728: }
1.1.1.33 root 14729: } else if(strncmp(tmp, "PATH=", 5) == 0) {
1.1.1.28 root 14730: if(env_path[0] != '\0') {
14731: sprintf(tmp, "PATH=%s", env_path);
14732: } else {
14733: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
14734: }
1.1.1.32 root 14735: path_added = 1;
1.1.1.33 root 14736: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
14737: prompt_added = 1;
1.1.1.28 root 14738: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
14739: if(env_temp[0] != '\0') {
14740: sprintf(tmp, "TEMP=%s", env_temp);
14741: } else {
14742: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
14743: }
1.1.1.32 root 14744: temp_added = 1;
1.1.1.33 root 14745: } else if(strncmp(tmp, "TMP=", 4) == 0) {
1.1.1.28 root 14746: if(env_temp[0] != '\0') {
14747: sprintf(tmp, "TMP=%s", env_temp);
14748: } else {
14749: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 14750: }
1.1.1.32 root 14751: tmp_added = 1;
1.1.1.33 root 14752: } else if(strncmp(tmp, "TZ=", 3) == 0) {
14753: char *env = getenv("MSDOS_TZ");
14754: if(env != NULL) {
14755: sprintf(tmp, "TZ=%s", env);
14756: }
14757: tz_added = 1;
1.1 root 14758: }
14759: int len = strlen(tmp);
1.1.1.14 root 14760: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 14761: fatalerror("too many environments\n");
14762: }
14763: memcpy(mem + (seg << 4) + ofs, tmp, len);
14764: ofs += len + 1;
14765: }
14766: }
1.1.1.32 root 14767: if(!append_added && env_append[0] != '\0') {
14768: #define SET_ENV(name, value) { \
14769: char tmp[ENV_SIZE]; \
14770: sprintf(tmp, "%s=%s", name, value); \
14771: int len = strlen(tmp); \
14772: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
14773: fatalerror("too many environments\n"); \
14774: } \
14775: memcpy(mem + (seg << 4) + ofs, tmp, len); \
14776: ofs += len + 1; \
14777: }
14778: SET_ENV("APPEND", env_append);
14779: }
14780: if(!comspec_added) {
14781: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
14782: }
1.1.1.33 root 14783: if(!lastdrive_added) {
14784: SET_ENV("LASTDRIVE", "Z");
14785: }
1.1.1.32 root 14786: if(!path_added) {
14787: SET_ENV("PATH", env_path);
14788: }
1.1.1.33 root 14789: if(!prompt_added) {
14790: SET_ENV("PROMPT", "$P$G");
14791: }
1.1.1.32 root 14792: if(!temp_added) {
14793: SET_ENV("TEMP", env_temp);
14794: }
14795: if(!tmp_added) {
14796: SET_ENV("TMP", env_temp);
14797: }
1.1.1.33 root 14798: if(!tz_added) {
14799: TIME_ZONE_INFORMATION tzi;
14800: HKEY hKey, hSubKey;
14801: char tzi_std_name[64];
14802: char tz_std[8] = "GMT";
14803: char tz_dlt[8] = "GST";
14804: char tz_value[32];
14805:
14806: // timezone name from GetTimeZoneInformation may not be english
14807: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
14808: setlocale(LC_CTYPE, "");
14809: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
14810:
14811: // get english timezone name from registry
14812: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
14813: for(DWORD i = 0; !tz_added; i++) {
14814: char reg_name[256], sub_key[1024], std_name[256];
14815: DWORD size;
14816: FILETIME ftTime;
14817: LONG result = RegEnumKeyEx(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
14818:
14819: if(result == ERROR_SUCCESS) {
14820: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
14821: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
14822: if(RegQueryValueEx(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
14823: // search english timezone name from table
14824: if (strcmp(std_name, tzi_std_name) == 0) {
14825: for(int j = 0; j < array_length(tz_table); j++) {
14826: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
14827: if(tz_table[j].std != NULL) {
14828: strcpy(tz_std, tz_table[j].std);
14829: }
14830: if(tz_table[j].dlt != NULL) {
14831: strcpy(tz_dlt, tz_table[j].dlt);
14832: }
14833: tz_added = 1;
14834: break;
14835: }
14836: }
14837: }
14838: }
14839: RegCloseKey(hSubKey);
14840: }
14841: } else if(result == ERROR_NO_MORE_ITEMS) {
14842: break;
14843: }
14844: }
14845: RegCloseKey(hKey);
14846: }
14847: if((tzi.Bias % 60) != 0) {
14848: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
14849: } else {
14850: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
14851: }
14852: if(daylight) {
14853: strcat(tz_value, tz_dlt);
14854: }
14855: SET_ENV("TZ", tz_value);
14856: }
1.1 root 14857: seg += (ENV_SIZE >> 4);
14858:
14859: // psp
1.1.1.33 root 14860: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
1.1 root 14861: current_psp = seg;
1.1.1.35! root 14862: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
! 14863: psp->parent_psp = current_psp;
1.1 root 14864: seg += (PSP_SIZE >> 4);
14865:
1.1.1.19 root 14866: // first free mcb in conventional memory
1.1.1.33 root 14867: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 14868: first_mcb = seg;
14869:
1.1.1.19 root 14870: // dummy mcb to link to umb
1.1.1.33 root 14871: #if 0
14872: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4)); // link umb
14873: #else
14874: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0); // unlink umb
14875: #endif
1.1.1.19 root 14876:
14877: // first free mcb in upper memory block
1.1.1.8 root 14878: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 14879:
1.1.1.29 root 14880: #ifdef SUPPORT_HMA
14881: // first free mcb in high memory area
14882: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14883: #endif
14884:
1.1.1.26 root 14885: // interrupt vector
14886: for(int i = 0; i < 0x80; i++) {
14887: *(UINT16 *)(mem + 4 * i + 0) = i;
14888: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
14889: }
1.1.1.35! root 14890: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffd:0018 irq0 (system timer)
1.1.1.26 root 14891: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
14892: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
14893: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
14894: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
14895: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
14896: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
14897: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
14898:
1.1.1.29 root 14899: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 14900: static const struct {
14901: UINT16 attributes;
14902: char *dev_name;
14903: } dummy_devices[] = {
14904: {0x8013, "CON "},
14905: {0x8000, "AUX "},
14906: {0xa0c0, "PRN "},
14907: {0x8008, "CLOCK$ "},
14908: {0x8000, "COM1 "},
14909: {0xa0c0, "LPT1 "},
14910: {0xa0c0, "LPT2 "},
14911: {0xa0c0, "LPT3 "},
14912: {0x8000, "COM2 "},
14913: {0x8000, "COM3 "},
14914: {0x8000, "COM4 "},
1.1.1.30 root 14915: // {0xc000, "CONFIG$ "},
14916: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 14917: };
14918: static const UINT8 dummy_device_routine[] = {
14919: // from NUL device of Windows 98 SE
14920: // or word ptr ES:[BX+03],0100
14921: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
14922: // retf
14923: 0xcb,
14924: };
1.1.1.29 root 14925: device_t *last = NULL;
1.1.1.32 root 14926: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 14927: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 14928: device->next_driver.w.l = 22 + 18 * (i + 1);
14929: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 14930: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 14931: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
14932: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 14933: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 14934: last = device;
14935: }
14936: if(last != NULL) {
14937: last->next_driver.w.l = 0;
14938: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 14939: }
1.1.1.29 root 14940: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 14941:
1.1.1.25 root 14942: // dos info
14943: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
14944: dos_info->magic_word = 1;
14945: dos_info->first_mcb = MEMORY_TOP >> 4;
14946: dos_info->first_dpb.w.l = 0;
14947: dos_info->first_dpb.w.h = DPB_TOP >> 4;
14948: dos_info->first_sft.w.l = 0;
14949: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.26 root 14950: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 3rd device in IO.SYS
1.1.1.25 root 14951: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 14952: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 14953: dos_info->con_device.w.h = DEVICE_TOP >> 4;
14954: dos_info->max_sector_len = 512;
14955: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
14956: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
14957: dos_info->cds.w.l = 0;
14958: dos_info->cds.w.h = CDS_TOP >> 4;
14959: dos_info->fcb_table.w.l = 0;
14960: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
14961: dos_info->last_drive = 'Z' - 'A' + 1;
14962: dos_info->buffers_x = 20;
14963: dos_info->buffers_y = 0;
14964: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 14965: dos_info->nul_device.next_driver.w.l = 22;
14966: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 14967: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 14968: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
14969: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 14970: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
14971: dos_info->disk_buf_heads.w.l = 0;
14972: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
14973: dos_info->first_umb_fcb = UMB_TOP >> 4;
14974: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 14975: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 14976:
14977: char *env;
14978: if((env = getenv("LASTDRIVE")) != NULL) {
14979: if(env[0] >= 'A' && env[0] <= 'Z') {
14980: dos_info->last_drive = env[0] - 'A' + 1;
14981: } else if(env[0] >= 'a' && env[0] <= 'z') {
14982: dos_info->last_drive = env[0] - 'a' + 1;
14983: }
14984: }
14985: if((env = getenv("windir")) != NULL) {
14986: if(env[0] >= 'A' && env[0] <= 'Z') {
14987: dos_info->boot_drive = env[0] - 'A' + 1;
14988: } else if(env[0] >= 'a' && env[0] <= 'z') {
14989: dos_info->boot_drive = env[0] - 'a' + 1;
14990: }
14991: }
14992: #if defined(HAS_I386)
14993: dos_info->i386_or_later = 1;
14994: #else
14995: dos_info->i386_or_later = 0;
14996: #endif
14997: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
14998:
1.1.1.27 root 14999: // ems (int 67h) and xms
1.1.1.25 root 15000: device_t *xms_device = (device_t *)(mem + XMS_TOP);
15001: xms_device->next_driver.w.l = 0xffff;
15002: xms_device->next_driver.w.h = 0xffff;
15003: xms_device->attributes = 0xc000;
1.1.1.29 root 15004: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
15005: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 15006: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
15007:
1.1.1.26 root 15008: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
15009: mem[XMS_TOP + 0x13] = 0x68;
15010: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 15011: #ifdef SUPPORT_XMS
15012: if(support_xms) {
1.1.1.26 root 15013: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
15014: mem[XMS_TOP + 0x16] = 0x69;
15015: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 15016: } else
15017: #endif
1.1.1.26 root 15018: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 15019: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 15020:
1.1.1.26 root 15021: // irq12 routine (mouse)
1.1.1.24 root 15022: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
15023: mem[0xfffd0 + 0x01] = 0x6a;
15024: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
15025: mem[0xfffd0 + 0x03] = 0xff;
15026: mem[0xfffd0 + 0x04] = 0xff;
15027: mem[0xfffd0 + 0x05] = 0xff;
15028: mem[0xfffd0 + 0x06] = 0xff;
15029: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
15030: mem[0xfffd0 + 0x08] = 0x6b;
15031: mem[0xfffd0 + 0x09] = 0xcf; // iret
15032:
1.1.1.27 root 15033: // case map routine
15034: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
15035: mem[0xfffd0 + 0x0b] = 0x6c;
15036: mem[0xfffd0 + 0x0c] = 0xcb; // retf
15037:
15038: // font read routine
15039: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
15040: mem[0xfffd0 + 0x0e] = 0x6d;
15041: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 15042:
1.1.1.32 root 15043: // error message read routine
15044: mem[0xfffd0 + 0x10] = 0xcd; // int 6eh (dummy)
15045: mem[0xfffd0 + 0x11] = 0x6e;
15046: mem[0xfffd0 + 0x12] = 0xcb; // retf
15047:
1.1.1.35! root 15048: // dummy loop to wait BIOS/DOS service is done
! 15049: mem[0xfffd0 + 0x13] = 0xe6; // out f7h, al
! 15050: mem[0xfffd0 + 0x14] = 0xf7;
! 15051: mem[0xfffd0 + 0x15] = 0x78; // js/jns -4
! 15052: mem[0xfffd0 + 0x16] = 0xfc;
! 15053: mem[0xfffd0 + 0x17] = 0xcb; // retf
! 15054:
1.1.1.26 root 15055: // irq0 routine (system time)
1.1.1.35! root 15056: mem[0xfffd0 + 0x18] = 0xcd; // int 1ch
! 15057: mem[0xfffd0 + 0x19] = 0x1c;
! 15058: mem[0xfffd0 + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008
! 15059: mem[0xfffd0 + 0x1b] = 0x08;
! 15060: mem[0xfffd0 + 0x1c] = 0x00;
! 15061: mem[0xfffd0 + 0x1d] = ((IRET_TOP >> 4) ) & 0xff;
! 15062: mem[0xfffd0 + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 15063:
1.1.1.26 root 15064: // boot routine
1.1 root 15065: mem[0xffff0] = 0xf4; // halt
15066: mem[0xffff1] = 0xcd; // int 21h
15067: mem[0xffff2] = 0x21;
15068: mem[0xffff3] = 0xcb; // retf
15069:
1.1.1.24 root 15070: mem[0xffff5] = '0'; // rom date
15071: mem[0xffff6] = '2';
15072: mem[0xffff7] = '/';
15073: mem[0xffff8] = '2';
15074: mem[0xffff9] = '2';
15075: mem[0xffffa] = '/';
15076: mem[0xffffb] = '0';
15077: mem[0xffffc] = '6';
15078: mem[0xffffe] = 0xfc; // machine id
15079: mem[0xfffff] = 0x00;
15080:
1.1 root 15081: // param block
15082: // + 0: param block (22bytes)
15083: // +24: fcb1/2 (20bytes)
15084: // +44: command tail (128bytes)
15085: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
15086: param->env_seg = 0;
15087: param->cmd_line.w.l = 44;
15088: param->cmd_line.w.h = (WORK_TOP >> 4);
15089: param->fcb1.w.l = 24;
15090: param->fcb1.w.h = (WORK_TOP >> 4);
15091: param->fcb2.w.l = 24;
15092: param->fcb2.w.h = (WORK_TOP >> 4);
15093:
15094: memset(mem + WORK_TOP + 24, 0x20, 20);
15095:
15096: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
15097: if(argc > 1) {
15098: sprintf(cmd_line->cmd, " %s", argv[1]);
15099: for(int i = 2; i < argc; i++) {
15100: char tmp[128];
15101: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
15102: strcpy(cmd_line->cmd, tmp);
15103: }
15104: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
15105: } else {
15106: cmd_line->len = 0;
15107: }
15108: cmd_line->cmd[cmd_line->len] = 0x0d;
15109:
15110: // system file table
1.1.1.21 root 15111: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
15112: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 15113:
1.1.1.19 root 15114: // disk buffer header (from DOSBox)
15115: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
15116: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
15117: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
15118: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
15119: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
15120:
1.1 root 15121: // current directory structure
15122: msdos_cds_update(_getdrive() - 1);
15123:
15124: // fcb table
15125: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 15126: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 15127:
1.1.1.17 root 15128: // nls stuff
15129: msdos_nls_tables_init();
1.1 root 15130:
15131: // execute command
1.1.1.28 root 15132: try {
15133: if(msdos_process_exec(argv[0], param, 0)) {
15134: fatalerror("'%s' not found\n", argv[0]);
15135: }
15136: } catch(...) {
15137: // we should not reach here :-(
15138: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 15139: }
15140: retval = 0;
15141: return(0);
15142: }
15143:
15144: #define remove_std_file(path) { \
15145: int fd = _open(path, _O_RDONLY | _O_BINARY); \
15146: if(fd != -1) { \
15147: _lseek(fd, 0, SEEK_END); \
15148: int size = _tell(fd); \
15149: _close(fd); \
15150: if(size == 0) { \
15151: remove(path); \
15152: } \
15153: } \
15154: }
15155:
15156: void msdos_finish()
15157: {
15158: for(int i = 0; i < MAX_FILES; i++) {
15159: if(file_handler[i].valid) {
15160: _close(i);
15161: }
15162: }
1.1.1.21 root 15163: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 15164: remove_std_file("stdaux.txt");
1.1.1.21 root 15165: #endif
15166: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 15167: remove_std_file("stdprn.txt");
15168: #endif
1.1.1.30 root 15169: #ifdef SUPPORT_XMS
15170: msdos_xms_finish();
15171: #endif
1.1 root 15172: msdos_dbcs_table_finish();
15173: }
15174:
15175: /* ----------------------------------------------------------------------------
15176: PC/AT hardware emulation
15177: ---------------------------------------------------------------------------- */
15178:
15179: void hardware_init()
15180: {
1.1.1.3 root 15181: CPU_INIT_CALL(CPU_MODEL);
1.1 root 15182: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 15183: m_IF = 1;
1.1.1.3 root 15184: #if defined(HAS_I386)
1.1 root 15185: cpu_type = (REG32(EDX) >> 8) & 0x0f;
15186: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 15187: #endif
15188: i386_set_a20_line(0);
1.1.1.14 root 15189:
1.1.1.19 root 15190: ems_init();
1.1.1.25 root 15191: dma_init();
1.1 root 15192: pic_init();
1.1.1.25 root 15193: pio_init();
1.1.1.8 root 15194: #ifdef PIT_ALWAYS_RUNNING
15195: pit_init();
15196: #else
1.1 root 15197: pit_active = 0;
15198: #endif
1.1.1.25 root 15199: sio_init();
1.1.1.8 root 15200: cmos_init();
15201: kbd_init();
1.1 root 15202: }
15203:
1.1.1.10 root 15204: void hardware_finish()
15205: {
15206: #if defined(HAS_I386)
15207: vtlb_free(m_vtlb);
15208: #endif
1.1.1.19 root 15209: ems_finish();
1.1.1.25 root 15210: sio_finish();
1.1.1.10 root 15211: }
15212:
1.1.1.28 root 15213: void hardware_release()
15214: {
15215: // release hardware resources when this program will be terminated abnormally
15216: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 15217: if(fp_debug_log != NULL) {
15218: fclose(fp_debug_log);
15219: fp_debug_log = NULL;
1.1.1.28 root 15220: }
15221: #endif
15222: #if defined(HAS_I386)
15223: vtlb_free(m_vtlb);
15224: #endif
15225: ems_release();
15226: sio_release();
15227: }
15228:
1.1 root 15229: void hardware_run()
15230: {
1.1.1.22 root 15231: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 15232: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.33 root 15233: fp_debug_log = fopen("debug.log", "w");
1.1.1.22 root 15234: #endif
1.1.1.3 root 15235: while(!m_halted) {
15236: #if defined(HAS_I386)
1.1 root 15237: CPU_EXECUTE_CALL(i386);
1.1.1.14 root 15238: if(m_eip != m_prev_eip) {
1.1.1.35! root 15239: idle_ops++;
! 15240: }
1.1.1.14 root 15241: #else
1.1.1.35! root 15242: CPU_EXECUTE_CALL(CPU_MODEL);
1.1.1.14 root 15243: if(m_pc != m_prevpc) {
1.1.1.35! root 15244: idle_ops++;
1.1.1.14 root 15245: }
1.1.1.35! root 15246: #endif
! 15247: if(++update_ops == UPDATE_OPS) {
1.1 root 15248: hardware_update();
1.1.1.35! root 15249: update_ops = 0;
1.1 root 15250: }
15251: }
1.1.1.22 root 15252: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 15253: if(fp_debug_log != NULL) {
15254: fclose(fp_debug_log);
15255: fp_debug_log = NULL;
1.1.1.28 root 15256: }
1.1.1.22 root 15257: #endif
1.1 root 15258: }
15259:
15260: void hardware_update()
15261: {
1.1.1.8 root 15262: static UINT32 prev_time = 0;
15263: UINT32 cur_time = timeGetTime();
15264:
15265: if(prev_time != cur_time) {
15266: // update pit and raise irq0
15267: #ifndef PIT_ALWAYS_RUNNING
15268: if(pit_active)
15269: #endif
15270: {
15271: if(pit_run(0, cur_time)) {
15272: pic_req(0, 0, 1);
15273: }
15274: pit_run(1, cur_time);
15275: pit_run(2, cur_time);
15276: }
1.1.1.24 root 15277:
1.1.1.25 root 15278: // update sio and raise irq4/3
1.1.1.29 root 15279: for(int c = 0; c < 4; c++) {
1.1.1.25 root 15280: sio_update(c);
15281: }
15282:
1.1.1.24 root 15283: // update keyboard and mouse
1.1.1.14 root 15284: static UINT32 prev_tick = 0;
15285: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 15286:
1.1.1.14 root 15287: if(prev_tick != cur_tick) {
15288: // update keyboard flags
15289: UINT8 state;
1.1.1.24 root 15290: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
15291: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
15292: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
15293: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
15294: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
15295: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
15296: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
15297: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 15298: mem[0x417] = state;
15299: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
15300: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
15301: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
15302: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 15303: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
15304: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 15305: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
15306: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
15307: mem[0x418] = state;
15308:
1.1.1.24 root 15309: // update console input if needed
1.1.1.34 root 15310: if(!key_changed || mouse.hidden == 0) {
1.1.1.24 root 15311: update_console_input();
15312: }
15313:
15314: // raise irq1 if key is pressed/released
15315: if(key_changed) {
1.1.1.8 root 15316: pic_req(0, 1, 1);
1.1.1.24 root 15317: key_changed = false;
15318: }
15319:
15320: // raise irq12 if mouse status is changed
15321: if(mouse.status & mouse.call_mask) {
1.1.1.34 root 15322: // if(mouse.hidden == 0) {
1.1.1.24 root 15323: pic_req(1, 4, 1);
15324: mouse.status_irq = mouse.status & mouse.call_mask;
1.1.1.34 root 15325: // }
1.1.1.24 root 15326: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 15327: }
1.1.1.24 root 15328:
1.1.1.14 root 15329: prev_tick = cur_tick;
1.1.1.8 root 15330: }
1.1.1.24 root 15331:
1.1.1.19 root 15332: // update daily timer counter
15333: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 15334:
1.1.1.8 root 15335: prev_time = cur_time;
1.1 root 15336: }
15337: }
15338:
1.1.1.19 root 15339: // ems
15340:
15341: void ems_init()
15342: {
15343: memset(ems_handles, 0, sizeof(ems_handles));
15344: memset(ems_pages, 0, sizeof(ems_pages));
15345: free_ems_pages = MAX_EMS_PAGES;
15346: }
15347:
15348: void ems_finish()
15349: {
1.1.1.28 root 15350: ems_release();
15351: }
15352:
15353: void ems_release()
15354: {
1.1.1.31 root 15355: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 15356: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 15357: free(ems_handles[i].buffer);
15358: ems_handles[i].buffer = NULL;
15359: }
15360: }
15361: }
15362:
15363: void ems_allocate_pages(int handle, int pages)
15364: {
15365: if(pages > 0) {
15366: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
15367: } else {
15368: ems_handles[handle].buffer = NULL;
15369: }
15370: ems_handles[handle].pages = pages;
15371: ems_handles[handle].allocated = true;
15372: free_ems_pages -= pages;
15373: }
15374:
15375: void ems_reallocate_pages(int handle, int pages)
15376: {
15377: if(ems_handles[handle].allocated) {
15378: if(ems_handles[handle].pages != pages) {
15379: UINT8 *new_buffer = NULL;
15380:
15381: if(pages > 0) {
15382: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
15383: }
1.1.1.32 root 15384: if(ems_handles[handle].buffer != NULL) {
15385: if(new_buffer != NULL) {
1.1.1.19 root 15386: if(pages > ems_handles[handle].pages) {
15387: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
15388: } else {
15389: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
15390: }
15391: }
15392: free(ems_handles[handle].buffer);
15393: ems_handles[handle].buffer = NULL;
15394: }
15395: free_ems_pages += ems_handles[handle].pages;
15396:
15397: ems_handles[handle].buffer = new_buffer;
15398: ems_handles[handle].pages = pages;
15399: free_ems_pages -= pages;
15400: }
15401: } else {
15402: ems_allocate_pages(handle, pages);
15403: }
15404: }
15405:
15406: void ems_release_pages(int handle)
15407: {
15408: if(ems_handles[handle].allocated) {
1.1.1.32 root 15409: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 15410: free(ems_handles[handle].buffer);
15411: ems_handles[handle].buffer = NULL;
15412: }
15413: free_ems_pages += ems_handles[handle].pages;
15414: ems_handles[handle].allocated = false;
15415: }
15416: }
15417:
15418: void ems_map_page(int physical, int handle, int logical)
15419: {
15420: if(ems_pages[physical].mapped) {
15421: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
15422: return;
15423: }
15424: ems_unmap_page(physical);
15425: }
1.1.1.32 root 15426: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 15427: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
15428: }
15429: ems_pages[physical].handle = handle;
15430: ems_pages[physical].page = logical;
15431: ems_pages[physical].mapped = true;
15432: }
15433:
15434: void ems_unmap_page(int physical)
15435: {
15436: if(ems_pages[physical].mapped) {
15437: int handle = ems_pages[physical].handle;
15438: int logical = ems_pages[physical].page;
15439:
1.1.1.32 root 15440: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 15441: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
15442: }
15443: ems_pages[physical].mapped = false;
15444: }
15445: }
15446:
1.1.1.25 root 15447: // dma
1.1 root 15448:
1.1.1.25 root 15449: void dma_init()
1.1 root 15450: {
1.1.1.26 root 15451: memset(dma, 0, sizeof(dma));
1.1.1.25 root 15452: for(int c = 0; c < 2; c++) {
1.1.1.26 root 15453: // for(int ch = 0; ch < 4; ch++) {
15454: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
15455: // }
1.1.1.25 root 15456: dma_reset(c);
15457: }
1.1 root 15458: }
15459:
1.1.1.25 root 15460: void dma_reset(int c)
1.1 root 15461: {
1.1.1.25 root 15462: dma[c].low_high = false;
15463: dma[c].cmd = dma[c].req = dma[c].tc = 0;
15464: dma[c].mask = 0xff;
15465: }
15466:
15467: void dma_write(int c, UINT32 addr, UINT8 data)
15468: {
15469: int ch = (addr >> 1) & 3;
15470: UINT8 bit = 1 << (data & 3);
15471:
15472: switch(addr & 0x0f) {
15473: case 0x00: case 0x02: case 0x04: case 0x06:
15474: if(dma[c].low_high) {
15475: dma[c].ch[ch].bareg.b.h = data;
1.1 root 15476: } else {
1.1.1.25 root 15477: dma[c].ch[ch].bareg.b.l = data;
15478: }
15479: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
15480: dma[c].low_high = !dma[c].low_high;
15481: break;
15482: case 0x01: case 0x03: case 0x05: case 0x07:
15483: if(dma[c].low_high) {
15484: dma[c].ch[ch].bcreg.b.h = data;
15485: } else {
15486: dma[c].ch[ch].bcreg.b.l = data;
15487: }
15488: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
15489: dma[c].low_high = !dma[c].low_high;
15490: break;
15491: case 0x08:
15492: // command register
15493: dma[c].cmd = data;
15494: break;
15495: case 0x09:
15496: // dma[c].request register
15497: if(data & 4) {
15498: if(!(dma[c].req & bit)) {
15499: dma[c].req |= bit;
15500: // dma_run(c, ch);
15501: }
15502: } else {
15503: dma[c].req &= ~bit;
15504: }
15505: break;
15506: case 0x0a:
15507: // single mask register
15508: if(data & 4) {
15509: dma[c].mask |= bit;
15510: } else {
15511: dma[c].mask &= ~bit;
15512: }
15513: break;
15514: case 0x0b:
15515: // mode register
15516: dma[c].ch[data & 3].mode = data;
15517: break;
15518: case 0x0c:
15519: dma[c].low_high = false;
15520: break;
15521: case 0x0d:
15522: // clear master
15523: dma_reset(c);
15524: break;
15525: case 0x0e:
15526: // clear mask register
15527: dma[c].mask = 0;
15528: break;
15529: case 0x0f:
15530: // all mask register
15531: dma[c].mask = data & 0x0f;
15532: break;
15533: }
15534: }
15535:
15536: UINT8 dma_read(int c, UINT32 addr)
15537: {
15538: int ch = (addr >> 1) & 3;
15539: UINT8 val = 0xff;
15540:
15541: switch(addr & 0x0f) {
15542: case 0x00: case 0x02: case 0x04: case 0x06:
15543: if(dma[c].low_high) {
15544: val = dma[c].ch[ch].areg.b.h;
15545: } else {
15546: val = dma[c].ch[ch].areg.b.l;
15547: }
15548: dma[c].low_high = !dma[c].low_high;
15549: return(val);
15550: case 0x01: case 0x03: case 0x05: case 0x07:
15551: if(dma[c].low_high) {
15552: val = dma[c].ch[ch].creg.b.h;
15553: } else {
15554: val = dma[c].ch[ch].creg.b.l;
15555: }
15556: dma[c].low_high = !dma[c].low_high;
15557: return(val);
15558: case 0x08:
15559: // status register
15560: val = (dma[c].req << 4) | dma[c].tc;
15561: dma[c].tc = 0;
15562: return(val);
15563: case 0x0d:
1.1.1.26 root 15564: // temporary register (intel 82374 does not support)
1.1.1.25 root 15565: return(dma[c].tmp & 0xff);
1.1.1.26 root 15566: case 0x0f:
15567: // mask register (intel 82374 does support)
15568: return(dma[c].mask);
1.1.1.25 root 15569: }
15570: return(0xff);
15571: }
15572:
15573: void dma_page_write(int c, int ch, UINT8 data)
15574: {
15575: dma[c].ch[ch].pagereg = data;
15576: }
15577:
15578: UINT8 dma_page_read(int c, int ch)
15579: {
15580: return(dma[c].ch[ch].pagereg);
15581: }
15582:
15583: void dma_run(int c, int ch)
15584: {
15585: UINT8 bit = 1 << ch;
15586:
15587: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
15588: // execute dma
15589: while(dma[c].req & bit) {
15590: if(ch == 0 && (dma[c].cmd & 0x01)) {
15591: // memory -> memory
15592: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
15593: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
15594:
15595: if(c == 0) {
15596: dma[c].tmp = read_byte(saddr);
15597: write_byte(daddr, dma[c].tmp);
15598: } else {
15599: dma[c].tmp = read_word(saddr << 1);
15600: write_word(daddr << 1, dma[c].tmp);
15601: }
15602: if(!(dma[c].cmd & 0x02)) {
15603: if(dma[c].ch[0].mode & 0x20) {
15604: dma[c].ch[0].areg.w--;
15605: if(dma[c].ch[0].areg.w == 0xffff) {
15606: dma[c].ch[0].pagereg--;
15607: }
15608: } else {
15609: dma[c].ch[0].areg.w++;
15610: if(dma[c].ch[0].areg.w == 0) {
15611: dma[c].ch[0].pagereg++;
15612: }
15613: }
15614: }
15615: if(dma[c].ch[1].mode & 0x20) {
15616: dma[c].ch[1].areg.w--;
15617: if(dma[c].ch[1].areg.w == 0xffff) {
15618: dma[c].ch[1].pagereg--;
15619: }
15620: } else {
15621: dma[c].ch[1].areg.w++;
15622: if(dma[c].ch[1].areg.w == 0) {
15623: dma[c].ch[1].pagereg++;
15624: }
15625: }
15626:
15627: // check dma condition
15628: if(dma[c].ch[0].creg.w-- == 0) {
15629: if(dma[c].ch[0].mode & 0x10) {
15630: // self initialize
15631: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
15632: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
15633: } else {
15634: // dma[c].mask |= bit;
15635: }
15636: }
15637: if(dma[c].ch[1].creg.w-- == 0) {
15638: // terminal count
15639: if(dma[c].ch[1].mode & 0x10) {
15640: // self initialize
15641: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
15642: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
15643: } else {
15644: dma[c].mask |= bit;
15645: }
15646: dma[c].req &= ~bit;
15647: dma[c].tc |= bit;
15648: }
15649: } else {
15650: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
15651:
15652: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
15653: // verify
15654: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
15655: // io -> memory
15656: if(c == 0) {
15657: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
15658: write_byte(addr, dma[c].tmp);
15659: } else {
15660: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
15661: write_word(addr << 1, dma[c].tmp);
15662: }
15663: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
15664: // memory -> io
15665: if(c == 0) {
15666: dma[c].tmp = read_byte(addr);
15667: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
15668: } else {
15669: dma[c].tmp = read_word(addr << 1);
15670: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
15671: }
15672: }
15673: if(dma[c].ch[ch].mode & 0x20) {
15674: dma[c].ch[ch].areg.w--;
15675: if(dma[c].ch[ch].areg.w == 0xffff) {
15676: dma[c].ch[ch].pagereg--;
15677: }
15678: } else {
15679: dma[c].ch[ch].areg.w++;
15680: if(dma[c].ch[ch].areg.w == 0) {
15681: dma[c].ch[ch].pagereg++;
15682: }
15683: }
15684:
15685: // check dma condition
15686: if(dma[c].ch[ch].creg.w-- == 0) {
15687: // terminal count
15688: if(dma[c].ch[ch].mode & 0x10) {
15689: // self initialize
15690: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
15691: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
15692: } else {
15693: dma[c].mask |= bit;
15694: }
15695: dma[c].req &= ~bit;
15696: dma[c].tc |= bit;
15697: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
15698: // single mode
15699: break;
15700: }
15701: }
15702: }
15703: }
15704: }
15705:
15706: // pic
15707:
15708: void pic_init()
15709: {
15710: memset(pic, 0, sizeof(pic));
15711: pic[0].imr = pic[1].imr = 0xff;
15712:
15713: // from bochs bios
15714: pic_write(0, 0, 0x11); // icw1 = 11h
15715: pic_write(0, 1, 0x08); // icw2 = 08h
15716: pic_write(0, 1, 0x04); // icw3 = 04h
15717: pic_write(0, 1, 0x01); // icw4 = 01h
15718: pic_write(0, 1, 0xb8); // ocw1 = b8h
15719: pic_write(1, 0, 0x11); // icw1 = 11h
15720: pic_write(1, 1, 0x70); // icw2 = 70h
15721: pic_write(1, 1, 0x02); // icw3 = 02h
15722: pic_write(1, 1, 0x01); // icw4 = 01h
15723: }
15724:
15725: void pic_write(int c, UINT32 addr, UINT8 data)
15726: {
15727: if(addr & 1) {
15728: if(pic[c].icw2_r) {
15729: // icw2
15730: pic[c].icw2 = data;
15731: pic[c].icw2_r = 0;
15732: } else if(pic[c].icw3_r) {
15733: // icw3
15734: pic[c].icw3 = data;
15735: pic[c].icw3_r = 0;
15736: } else if(pic[c].icw4_r) {
15737: // icw4
15738: pic[c].icw4 = data;
15739: pic[c].icw4_r = 0;
15740: } else {
15741: // ocw1
1.1 root 15742: pic[c].imr = data;
15743: }
15744: } else {
15745: if(data & 0x10) {
15746: // icw1
15747: pic[c].icw1 = data;
15748: pic[c].icw2_r = 1;
15749: pic[c].icw3_r = (data & 2) ? 0 : 1;
15750: pic[c].icw4_r = data & 1;
15751: pic[c].irr = 0;
15752: pic[c].isr = 0;
15753: pic[c].imr = 0;
15754: pic[c].prio = 0;
15755: if(!(pic[c].icw1 & 1)) {
15756: pic[c].icw4 = 0;
15757: }
15758: pic[c].ocw3 = 0;
15759: } else if(data & 8) {
15760: // ocw3
15761: if(!(data & 2)) {
15762: data = (data & ~1) | (pic[c].ocw3 & 1);
15763: }
15764: if(!(data & 0x40)) {
15765: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
15766: }
15767: pic[c].ocw3 = data;
15768: } else {
15769: // ocw2
15770: int level = 0;
15771: if(data & 0x40) {
15772: level = data & 7;
15773: } else {
15774: if(!pic[c].isr) {
15775: return;
15776: }
15777: level = pic[c].prio;
15778: while(!(pic[c].isr & (1 << level))) {
15779: level = (level + 1) & 7;
15780: }
15781: }
15782: if(data & 0x80) {
15783: pic[c].prio = (level + 1) & 7;
15784: }
15785: if(data & 0x20) {
15786: pic[c].isr &= ~(1 << level);
15787: }
15788: }
15789: }
15790: pic_update();
15791: }
15792:
15793: UINT8 pic_read(int c, UINT32 addr)
15794: {
15795: if(addr & 1) {
15796: return(pic[c].imr);
15797: } else {
15798: // polling mode is not supported...
15799: //if(pic[c].ocw3 & 4) {
15800: // return ???;
15801: //}
15802: if(pic[c].ocw3 & 1) {
15803: return(pic[c].isr);
15804: } else {
15805: return(pic[c].irr);
15806: }
15807: }
15808: }
15809:
15810: void pic_req(int c, int level, int signal)
15811: {
15812: if(signal) {
15813: pic[c].irr |= (1 << level);
15814: } else {
15815: pic[c].irr &= ~(1 << level);
15816: }
15817: pic_update();
15818: }
15819:
15820: int pic_ack()
15821: {
15822: // ack (INTA=L)
15823: pic[pic_req_chip].isr |= pic_req_bit;
15824: pic[pic_req_chip].irr &= ~pic_req_bit;
15825: if(pic_req_chip > 0) {
15826: // update isr and irr of master
15827: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
15828: pic[pic_req_chip - 1].isr |= slave;
15829: pic[pic_req_chip - 1].irr &= ~slave;
15830: }
15831: //if(pic[pic_req_chip].icw4 & 1) {
15832: // 8086 mode
15833: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
15834: //} else {
15835: // // 8080 mode
15836: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
15837: // if(pic[pic_req_chip].icw1 & 4) {
15838: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
15839: // } else {
15840: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
15841: // }
15842: // vector = 0xcd | (addr << 8);
15843: //}
15844: if(pic[pic_req_chip].icw4 & 2) {
15845: // auto eoi
15846: pic[pic_req_chip].isr &= ~pic_req_bit;
15847: }
15848: return(vector);
15849: }
15850:
15851: void pic_update()
15852: {
15853: for(int c = 0; c < 2; c++) {
15854: UINT8 irr = pic[c].irr;
15855: if(c + 1 < 2) {
15856: // this is master
15857: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
15858: // request from slave
15859: irr |= 1 << (pic[c + 1].icw3 & 7);
15860: }
15861: }
15862: irr &= (~pic[c].imr);
15863: if(!irr) {
15864: break;
15865: }
15866: if(!(pic[c].ocw3 & 0x20)) {
15867: irr |= pic[c].isr;
15868: }
15869: int level = pic[c].prio;
15870: UINT8 bit = 1 << level;
15871: while(!(irr & bit)) {
15872: level = (level + 1) & 7;
15873: bit = 1 << level;
15874: }
15875: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
15876: // check slave
15877: continue;
15878: }
15879: if(pic[c].isr & bit) {
15880: break;
15881: }
15882: // interrupt request
15883: pic_req_chip = c;
15884: pic_req_level = level;
15885: pic_req_bit = bit;
1.1.1.3 root 15886: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 15887: return;
15888: }
1.1.1.3 root 15889: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 15890: }
1.1 root 15891:
1.1.1.25 root 15892: // pio
15893:
15894: void pio_init()
15895: {
1.1.1.26 root 15896: memset(pio, 0, sizeof(pio));
1.1.1.25 root 15897: for(int c = 0; c < 2; c++) {
15898: pio[c].stat = 0xde;
15899: pio[c].ctrl = 0x0c;
15900: }
15901: }
15902:
15903: void pio_write(int c, UINT32 addr, UINT8 data)
15904: {
15905: switch(addr & 3) {
15906: case 0:
15907: pio[c].data = data;
15908: break;
15909: case 2:
15910: pio[c].ctrl = data;
15911: break;
15912: }
15913: }
15914:
15915: UINT8 pio_read(int c, UINT32 addr)
15916: {
15917: switch(addr & 3) {
15918: case 0:
15919: return(pio[c].data);
15920: case 1:
15921: return(pio[c].stat);
15922: case 2:
15923: return(pio[c].ctrl);
15924: }
15925: return(0xff);
15926: }
15927:
1.1 root 15928: // pit
15929:
1.1.1.22 root 15930: #define PIT_FREQ 1193182ULL
1.1 root 15931: #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)
15932:
15933: void pit_init()
15934: {
1.1.1.8 root 15935: memset(pit, 0, sizeof(pit));
1.1 root 15936: for(int ch = 0; ch < 3; ch++) {
15937: pit[ch].count = 0x10000;
15938: pit[ch].ctrl_reg = 0x34;
15939: pit[ch].mode = 3;
15940: }
15941:
15942: // from bochs bios
15943: pit_write(3, 0x34);
15944: pit_write(0, 0x00);
15945: pit_write(0, 0x00);
15946: }
15947:
15948: void pit_write(int ch, UINT8 val)
15949: {
1.1.1.8 root 15950: #ifndef PIT_ALWAYS_RUNNING
1.1 root 15951: if(!pit_active) {
15952: pit_active = 1;
15953: pit_init();
15954: }
1.1.1.8 root 15955: #endif
1.1 root 15956: switch(ch) {
15957: case 0:
15958: case 1:
15959: case 2:
15960: // write count register
15961: if(!pit[ch].low_write && !pit[ch].high_write) {
15962: if(pit[ch].ctrl_reg & 0x10) {
15963: pit[ch].low_write = 1;
15964: }
15965: if(pit[ch].ctrl_reg & 0x20) {
15966: pit[ch].high_write = 1;
15967: }
15968: }
15969: if(pit[ch].low_write) {
15970: pit[ch].count_reg = val;
15971: pit[ch].low_write = 0;
15972: } else if(pit[ch].high_write) {
15973: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
15974: pit[ch].count_reg = val << 8;
15975: } else {
15976: pit[ch].count_reg |= val << 8;
15977: }
15978: pit[ch].high_write = 0;
15979: }
15980: // start count
1.1.1.8 root 15981: if(!pit[ch].low_write && !pit[ch].high_write) {
15982: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
15983: pit[ch].count = PIT_COUNT_VALUE(ch);
15984: pit[ch].prev_time = timeGetTime();
15985: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 15986: }
15987: }
15988: break;
15989: case 3: // ctrl reg
15990: if((val & 0xc0) == 0xc0) {
15991: // i8254 read-back command
15992: for(ch = 0; ch < 3; ch++) {
15993: if(!(val & 0x10) && !pit[ch].status_latched) {
15994: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
15995: pit[ch].status_latched = 1;
15996: }
15997: if(!(val & 0x20) && !pit[ch].count_latched) {
15998: pit_latch_count(ch);
15999: }
16000: }
16001: break;
16002: }
16003: ch = (val >> 6) & 3;
16004: if(val & 0x30) {
1.1.1.35! root 16005: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
1.1 root 16006: pit[ch].mode = modes[(val >> 1) & 7];
16007: pit[ch].count_latched = 0;
16008: pit[ch].low_read = pit[ch].high_read = 0;
16009: pit[ch].low_write = pit[ch].high_write = 0;
16010: pit[ch].ctrl_reg = val;
16011: // stop count
1.1.1.8 root 16012: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 16013: pit[ch].count_reg = 0;
16014: } else if(!pit[ch].count_latched) {
16015: pit_latch_count(ch);
16016: }
16017: break;
16018: }
16019: }
16020:
16021: UINT8 pit_read(int ch)
16022: {
1.1.1.8 root 16023: #ifndef PIT_ALWAYS_RUNNING
1.1 root 16024: if(!pit_active) {
16025: pit_active = 1;
16026: pit_init();
16027: }
1.1.1.8 root 16028: #endif
1.1 root 16029: switch(ch) {
16030: case 0:
16031: case 1:
16032: case 2:
16033: if(pit[ch].status_latched) {
16034: pit[ch].status_latched = 0;
16035: return(pit[ch].status);
16036: }
16037: // if not latched, through current count
16038: if(!pit[ch].count_latched) {
16039: if(!pit[ch].low_read && !pit[ch].high_read) {
16040: pit_latch_count(ch);
16041: }
16042: }
16043: // return latched count
16044: if(pit[ch].low_read) {
16045: pit[ch].low_read = 0;
16046: if(!pit[ch].high_read) {
16047: pit[ch].count_latched = 0;
16048: }
16049: return(pit[ch].latch & 0xff);
16050: } else if(pit[ch].high_read) {
16051: pit[ch].high_read = 0;
16052: pit[ch].count_latched = 0;
16053: return((pit[ch].latch >> 8) & 0xff);
16054: }
16055: }
16056: return(0xff);
16057: }
16058:
1.1.1.8 root 16059: int pit_run(int ch, UINT32 cur_time)
1.1 root 16060: {
1.1.1.8 root 16061: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 16062: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 16063: pit[ch].prev_time = pit[ch].expired_time;
16064: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
16065: if(cur_time >= pit[ch].expired_time) {
16066: pit[ch].prev_time = cur_time;
16067: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 16068: }
1.1.1.8 root 16069: return(1);
1.1 root 16070: }
1.1.1.8 root 16071: return(0);
1.1 root 16072: }
16073:
16074: void pit_latch_count(int ch)
16075: {
1.1.1.8 root 16076: if(pit[ch].expired_time != 0) {
1.1.1.26 root 16077: UINT32 cur_time = timeGetTime();
1.1.1.8 root 16078: pit_run(ch, cur_time);
16079: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 16080: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
16081:
16082: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
16083: // decrement counter in 1msec period
16084: if(pit[ch].next_latch == 0) {
16085: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
16086: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
16087: }
16088: if(pit[ch].latch > pit[ch].next_latch) {
16089: pit[ch].latch--;
16090: }
16091: } else {
16092: pit[ch].prev_latch = pit[ch].latch = latch;
16093: pit[ch].next_latch = 0;
16094: }
1.1.1.8 root 16095: } else {
16096: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 16097: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 16098: }
16099: pit[ch].count_latched = 1;
16100: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
16101: // lower byte
16102: pit[ch].low_read = 1;
16103: pit[ch].high_read = 0;
16104: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
16105: // upper byte
16106: pit[ch].low_read = 0;
16107: pit[ch].high_read = 1;
16108: } else {
16109: // lower -> upper
1.1.1.14 root 16110: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 16111: }
16112: }
16113:
1.1.1.8 root 16114: int pit_get_expired_time(int ch)
1.1 root 16115: {
1.1.1.22 root 16116: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
16117: UINT64 val = pit[ch].accum >> 10;
16118: pit[ch].accum -= val << 10;
16119: return((val != 0) ? val : 1);
1.1.1.8 root 16120: }
16121:
1.1.1.25 root 16122: // sio
16123:
16124: void sio_init()
16125: {
1.1.1.26 root 16126: memset(sio, 0, sizeof(sio));
16127: memset(sio_mt, 0, sizeof(sio_mt));
16128:
1.1.1.29 root 16129: for(int c = 0; c < 4; c++) {
1.1.1.25 root 16130: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
16131: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
16132:
16133: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
16134: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 16135: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
16136: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 16137: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
16138: sio[c].irq_identify = 0x01; // no pending irq
16139:
16140: InitializeCriticalSection(&sio_mt[c].csSendData);
16141: InitializeCriticalSection(&sio_mt[c].csRecvData);
16142: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
16143: InitializeCriticalSection(&sio_mt[c].csLineStat);
16144: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
16145: InitializeCriticalSection(&sio_mt[c].csModemStat);
16146:
1.1.1.26 root 16147: if(sio_port_number[c] != 0) {
1.1.1.25 root 16148: sio[c].channel = c;
16149: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
16150: }
16151: }
16152: }
16153:
16154: void sio_finish()
16155: {
1.1.1.29 root 16156: for(int c = 0; c < 4; c++) {
1.1.1.25 root 16157: if(sio_mt[c].hThread != NULL) {
16158: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
16159: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 16160: sio_mt[c].hThread = NULL;
1.1.1.25 root 16161: }
16162: DeleteCriticalSection(&sio_mt[c].csSendData);
16163: DeleteCriticalSection(&sio_mt[c].csRecvData);
16164: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
16165: DeleteCriticalSection(&sio_mt[c].csLineStat);
16166: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
16167: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 16168: }
16169: sio_release();
16170: }
16171:
16172: void sio_release()
16173: {
1.1.1.29 root 16174: for(int c = 0; c < 4; c++) {
1.1.1.28 root 16175: // sio_thread() may access the resources :-(
1.1.1.32 root 16176: bool running = (sio_mt[c].hThread != NULL);
16177:
16178: if(running) {
16179: EnterCriticalSection(&sio_mt[c].csSendData);
16180: }
16181: if(sio[c].send_buffer != NULL) {
16182: sio[c].send_buffer->release();
16183: delete sio[c].send_buffer;
16184: sio[c].send_buffer = NULL;
16185: }
16186: if(running) {
16187: LeaveCriticalSection(&sio_mt[c].csSendData);
16188: EnterCriticalSection(&sio_mt[c].csRecvData);
16189: }
16190: if(sio[c].recv_buffer != NULL) {
16191: sio[c].recv_buffer->release();
16192: delete sio[c].recv_buffer;
16193: sio[c].recv_buffer = NULL;
16194: }
16195: if(running) {
16196: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 16197: }
1.1.1.25 root 16198: }
16199: }
16200:
16201: void sio_write(int c, UINT32 addr, UINT8 data)
16202: {
16203: switch(addr & 7) {
16204: case 0:
16205: if(sio[c].selector & 0x80) {
16206: if(sio[c].divisor.b.l != data) {
16207: EnterCriticalSection(&sio_mt[c].csLineCtrl);
16208: sio[c].divisor.b.l = data;
16209: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
16210: }
16211: } else {
16212: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 16213: if(sio[c].send_buffer != NULL) {
16214: sio[c].send_buffer->write(data);
16215: }
1.1.1.25 root 16216: // transmitter holding/shift registers are not empty
16217: sio[c].line_stat_buf &= ~0x60;
16218: LeaveCriticalSection(&sio_mt[c].csSendData);
16219:
16220: if(sio[c].irq_enable & 0x02) {
16221: sio_update_irq(c);
16222: }
16223: }
16224: break;
16225: case 1:
16226: if(sio[c].selector & 0x80) {
16227: if(sio[c].divisor.b.h != data) {
16228: EnterCriticalSection(&sio_mt[c].csLineCtrl);
16229: sio[c].divisor.b.h = data;
16230: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
16231: }
16232: } else {
16233: if(sio[c].irq_enable != data) {
16234: sio[c].irq_enable = data;
16235: sio_update_irq(c);
16236: }
16237: }
16238: break;
16239: case 3:
16240: {
16241: UINT8 line_ctrl = data & 0x3f;
16242: bool set_brk = ((data & 0x40) != 0);
16243:
16244: if(sio[c].line_ctrl != line_ctrl) {
16245: EnterCriticalSection(&sio_mt[c].csLineCtrl);
16246: sio[c].line_ctrl = line_ctrl;
16247: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
16248: }
16249: if(sio[c].set_brk != set_brk) {
16250: EnterCriticalSection(&sio_mt[c].csModemCtrl);
16251: sio[c].set_brk = set_brk;
16252: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
16253: }
16254: }
16255: sio[c].selector = data;
16256: break;
16257: case 4:
16258: {
16259: bool set_dtr = ((data & 0x01) != 0);
16260: bool set_rts = ((data & 0x02) != 0);
16261:
16262: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 16263: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 16264: sio[c].set_dtr = set_dtr;
16265: sio[c].set_rts = set_rts;
1.1.1.26 root 16266: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
16267:
16268: bool state_changed = false;
16269:
16270: EnterCriticalSection(&sio_mt[c].csModemStat);
16271: if(set_dtr) {
16272: sio[c].modem_stat |= 0x20; // dsr on
16273: } else {
16274: sio[c].modem_stat &= ~0x20; // dsr off
16275: }
16276: if(set_rts) {
16277: sio[c].modem_stat |= 0x10; // cts on
16278: } else {
16279: sio[c].modem_stat &= ~0x10; // cts off
16280: }
16281: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
16282: if(!(sio[c].modem_stat & 0x02)) {
16283: if(sio[c].irq_enable & 0x08) {
16284: state_changed = true;
16285: }
16286: sio[c].modem_stat |= 0x02;
16287: }
16288: }
16289: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
16290: if(!(sio[c].modem_stat & 0x01)) {
16291: if(sio[c].irq_enable & 0x08) {
16292: state_changed = true;
16293: }
16294: sio[c].modem_stat |= 0x01;
16295: }
16296: }
16297: LeaveCriticalSection(&sio_mt[c].csModemStat);
16298:
16299: if(state_changed) {
16300: sio_update_irq(c);
16301: }
1.1.1.25 root 16302: }
16303: }
16304: sio[c].modem_ctrl = data;
16305: break;
16306: case 7:
16307: sio[c].scratch = data;
16308: break;
16309: }
16310: }
16311:
16312: UINT8 sio_read(int c, UINT32 addr)
16313: {
16314: switch(addr & 7) {
16315: case 0:
16316: if(sio[c].selector & 0x80) {
16317: return(sio[c].divisor.b.l);
16318: } else {
16319: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 16320: UINT8 data = 0;
16321: if(sio[c].recv_buffer != NULL) {
16322: data = sio[c].recv_buffer->read();
16323: }
1.1.1.25 root 16324: // data is not ready
16325: sio[c].line_stat_buf &= ~0x01;
16326: LeaveCriticalSection(&sio_mt[c].csRecvData);
16327:
16328: if(sio[c].irq_enable & 0x01) {
16329: sio_update_irq(c);
16330: }
16331: return(data);
16332: }
16333: case 1:
16334: if(sio[c].selector & 0x80) {
16335: return(sio[c].divisor.b.h);
16336: } else {
16337: return(sio[c].irq_enable);
16338: }
16339: case 2:
16340: return(sio[c].irq_identify);
16341: case 3:
16342: return(sio[c].selector);
16343: case 4:
16344: return(sio[c].modem_ctrl);
16345: case 5:
16346: {
16347: EnterCriticalSection(&sio_mt[c].csLineStat);
16348: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
16349: sio[c].line_stat_err = 0x00;
16350: LeaveCriticalSection(&sio_mt[c].csLineStat);
16351:
16352: bool state_changed = false;
16353:
16354: if((sio[c].line_stat_buf & 0x60) == 0x00) {
16355: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 16356: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 16357: // transmitter holding register will be empty first
16358: if(sio[c].irq_enable & 0x02) {
16359: state_changed = true;
16360: }
16361: sio[c].line_stat_buf |= 0x20;
16362: }
16363: LeaveCriticalSection(&sio_mt[c].csSendData);
16364: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
16365: // transmitter shift register will be empty later
16366: sio[c].line_stat_buf |= 0x40;
16367: }
16368: if(!(sio[c].line_stat_buf & 0x01)) {
16369: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 16370: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 16371: // data is ready
16372: if(sio[c].irq_enable & 0x01) {
16373: state_changed = true;
16374: }
16375: sio[c].line_stat_buf |= 0x01;
16376: }
16377: LeaveCriticalSection(&sio_mt[c].csRecvData);
16378: }
16379: if(state_changed) {
16380: sio_update_irq(c);
16381: }
16382: return(val);
16383: }
16384: case 6:
16385: {
16386: EnterCriticalSection(&sio_mt[c].csModemStat);
16387: UINT8 val = sio[c].modem_stat;
16388: sio[c].modem_stat &= 0xf0;
16389: sio[c].prev_modem_stat = sio[c].modem_stat;
16390: LeaveCriticalSection(&sio_mt[c].csModemStat);
16391:
16392: if(sio[c].modem_ctrl & 0x10) {
16393: // loop-back
16394: val &= 0x0f;
16395: val |= (sio[c].modem_ctrl & 0x0c) << 4;
16396: val |= (sio[c].modem_ctrl & 0x01) << 5;
16397: val |= (sio[c].modem_ctrl & 0x02) << 3;
16398: }
16399: return(val);
16400: }
16401: case 7:
16402: return(sio[c].scratch);
16403: }
16404: return(0xff);
16405: }
16406:
16407: void sio_update(int c)
16408: {
16409: if((sio[c].line_stat_buf & 0x60) == 0x00) {
16410: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 16411: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 16412: // transmitter holding/shift registers will be empty
16413: sio[c].line_stat_buf |= 0x60;
16414: }
16415: LeaveCriticalSection(&sio_mt[c].csSendData);
16416: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
16417: // transmitter shift register will be empty
16418: sio[c].line_stat_buf |= 0x40;
16419: }
16420: if(!(sio[c].line_stat_buf & 0x01)) {
16421: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 16422: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 16423: // data is ready
16424: sio[c].line_stat_buf |= 0x01;
16425: }
16426: LeaveCriticalSection(&sio_mt[c].csRecvData);
16427: }
16428: sio_update_irq(c);
16429: }
16430:
16431: void sio_update_irq(int c)
16432: {
16433: int level = -1;
16434:
16435: if(sio[c].irq_enable & 0x08) {
16436: EnterCriticalSection(&sio_mt[c].csModemStat);
16437: if((sio[c].modem_stat & 0x0f) != 0) {
16438: level = 0;
16439: }
16440: EnterCriticalSection(&sio_mt[c].csModemStat);
16441: }
16442: if(sio[c].irq_enable & 0x02) {
16443: if(sio[c].line_stat_buf & 0x20) {
16444: level = 1;
16445: }
16446: }
16447: if(sio[c].irq_enable & 0x01) {
16448: if(sio[c].line_stat_buf & 0x01) {
16449: level = 2;
16450: }
16451: }
16452: if(sio[c].irq_enable & 0x04) {
16453: EnterCriticalSection(&sio_mt[c].csLineStat);
16454: if(sio[c].line_stat_err != 0) {
16455: level = 3;
16456: }
16457: LeaveCriticalSection(&sio_mt[c].csLineStat);
16458: }
1.1.1.29 root 16459:
16460: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 16461: if(level != -1) {
16462: sio[c].irq_identify = level << 1;
1.1.1.29 root 16463: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 16464: } else {
16465: sio[c].irq_identify = 1;
1.1.1.29 root 16466: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 16467: }
16468: }
16469:
16470: DWORD WINAPI sio_thread(void *lpx)
16471: {
16472: volatile sio_t *p = (sio_t *)lpx;
16473: sio_mt_t *q = &sio_mt[p->channel];
16474:
16475: char name[] = "COM1";
1.1.1.26 root 16476: name[3] = '0' + sio_port_number[p->channel];
16477: HANDLE hComm = NULL;
16478: COMMPROP commProp;
16479: DCB dcb;
16480: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
16481: BYTE bytBuffer[SIO_BUFFER_SIZE];
16482:
16483: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
16484: if(GetCommProperties(hComm, &commProp)) {
16485: dwSettableBaud = commProp.dwSettableBaud;
16486: }
1.1.1.25 root 16487: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 16488: // EscapeCommFunction(hComm, SETRTS);
16489: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 16490:
16491: while(!m_halted) {
16492: // setup comm port
16493: bool comm_state_changed = false;
16494:
16495: EnterCriticalSection(&q->csLineCtrl);
16496: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
16497: p->prev_divisor = p->divisor.w;
16498: p->prev_line_ctrl = p->line_ctrl;
16499: comm_state_changed = true;
16500: }
16501: LeaveCriticalSection(&q->csLineCtrl);
16502:
16503: if(comm_state_changed) {
1.1.1.26 root 16504: if(GetCommState(hComm, &dcb)) {
16505: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
16506: DWORD baud = 115200 / p->prev_divisor;
16507: dcb.BaudRate = 9600; // default
16508:
16509: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
16510: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
16511: // 134.5bps is not supported ???
16512: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
16513: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
16514: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
16515: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
16516: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
16517: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
16518: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
16519: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
16520: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
16521: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
16522: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
16523: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
16524: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
16525:
16526: switch(p->prev_line_ctrl & 0x03) {
16527: case 0x00: dcb.ByteSize = 5; break;
16528: case 0x01: dcb.ByteSize = 6; break;
16529: case 0x02: dcb.ByteSize = 7; break;
16530: case 0x03: dcb.ByteSize = 8; break;
16531: }
16532: switch(p->prev_line_ctrl & 0x04) {
16533: case 0x00: dcb.StopBits = ONESTOPBIT; break;
16534: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
16535: }
16536: switch(p->prev_line_ctrl & 0x38) {
16537: case 0x08: dcb.Parity = ODDPARITY; break;
16538: case 0x18: dcb.Parity = EVENPARITY; break;
16539: case 0x28: dcb.Parity = MARKPARITY; break;
16540: case 0x38: dcb.Parity = SPACEPARITY; break;
16541: default: dcb.Parity = NOPARITY; break;
16542: }
16543: dcb.fBinary = TRUE;
16544: dcb.fParity = (dcb.Parity != NOPARITY);
16545: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
16546: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
16547: dcb.fDsrSensitivity = FALSE;//TRUE;
16548: dcb.fTXContinueOnXoff = TRUE;
16549: dcb.fOutX = dcb.fInX = FALSE;
16550: dcb.fErrorChar = FALSE;
16551: dcb.fNull = FALSE;
16552: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
16553: dcb.fAbortOnError = FALSE;
16554:
16555: SetCommState(hComm, &dcb);
1.1.1.25 root 16556: }
16557:
16558: // check again to apply all comm state changes
16559: Sleep(10);
16560: continue;
16561: }
16562:
16563: // set comm pins
16564: bool change_brk = false;
1.1.1.26 root 16565: // bool change_rts = false;
16566: // bool change_dtr = false;
1.1.1.25 root 16567:
16568: EnterCriticalSection(&q->csModemCtrl);
16569: if(p->prev_set_brk != p->set_brk) {
16570: p->prev_set_brk = p->set_brk;
16571: change_brk = true;
16572: }
1.1.1.26 root 16573: // if(p->prev_set_rts != p->set_rts) {
16574: // p->prev_set_rts = p->set_rts;
16575: // change_rts = true;
16576: // }
16577: // if(p->prev_set_dtr != p->set_dtr) {
16578: // p->prev_set_dtr = p->set_dtr;
16579: // change_dtr = true;
16580: // }
1.1.1.25 root 16581: LeaveCriticalSection(&q->csModemCtrl);
16582:
16583: if(change_brk) {
1.1.1.26 root 16584: static UINT32 clear_time = 0;
16585: if(p->prev_set_brk) {
16586: EscapeCommFunction(hComm, SETBREAK);
16587: clear_time = timeGetTime() + 200;
16588: } else {
16589: // keep break for at least 200msec
16590: UINT32 cur_time = timeGetTime();
16591: if(clear_time > cur_time) {
16592: Sleep(clear_time - cur_time);
16593: }
16594: EscapeCommFunction(hComm, CLRBREAK);
16595: }
1.1.1.25 root 16596: }
1.1.1.26 root 16597: // if(change_rts) {
16598: // if(p->prev_set_rts) {
16599: // EscapeCommFunction(hComm, SETRTS);
16600: // } else {
16601: // EscapeCommFunction(hComm, CLRRTS);
16602: // }
16603: // }
16604: // if(change_dtr) {
16605: // if(p->prev_set_dtr) {
16606: // EscapeCommFunction(hComm, SETDTR);
16607: // } else {
16608: // EscapeCommFunction(hComm, CLRDTR);
16609: // }
16610: // }
1.1.1.25 root 16611:
16612: // get comm pins
16613: DWORD dwModemStat = 0;
16614:
16615: if(GetCommModemStatus(hComm, &dwModemStat)) {
16616: EnterCriticalSection(&q->csModemStat);
16617: if(dwModemStat & MS_RLSD_ON) {
16618: p->modem_stat |= 0x80;
16619: } else {
16620: p->modem_stat &= ~0x80;
16621: }
16622: if(dwModemStat & MS_RING_ON) {
16623: p->modem_stat |= 0x40;
16624: } else {
16625: p->modem_stat &= ~0x40;
16626: }
1.1.1.26 root 16627: // if(dwModemStat & MS_DSR_ON) {
16628: // p->modem_stat |= 0x20;
16629: // } else {
16630: // p->modem_stat &= ~0x20;
16631: // }
16632: // if(dwModemStat & MS_CTS_ON) {
16633: // p->modem_stat |= 0x10;
16634: // } else {
16635: // p->modem_stat &= ~0x10;
16636: // }
1.1.1.25 root 16637: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
16638: p->modem_stat |= 0x08;
16639: }
16640: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
16641: p->modem_stat |= 0x04;
16642: }
1.1.1.26 root 16643: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
16644: // p->modem_stat |= 0x02;
16645: // }
16646: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
16647: // p->modem_stat |= 0x01;
16648: // }
1.1.1.25 root 16649: LeaveCriticalSection(&q->csModemStat);
16650: }
16651:
16652: // send data
16653: DWORD dwSend = 0;
16654:
16655: EnterCriticalSection(&q->csSendData);
1.1.1.32 root 16656: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 16657: bytBuffer[dwSend++] = p->send_buffer->read();
16658: }
16659: LeaveCriticalSection(&q->csSendData);
16660:
16661: if(dwSend != 0) {
16662: DWORD dwWritten = 0;
16663: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
16664: }
16665:
16666: // get line status and recv data
16667: DWORD dwLineStat = 0;
16668: COMSTAT comStat;
16669:
16670: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
16671: EnterCriticalSection(&q->csLineStat);
16672: if(dwLineStat & CE_BREAK) {
16673: p->line_stat_err |= 0x10;
16674: }
16675: if(dwLineStat & CE_FRAME) {
16676: p->line_stat_err |= 0x08;
16677: }
16678: if(dwLineStat & CE_RXPARITY) {
16679: p->line_stat_err |= 0x04;
16680: }
16681: if(dwLineStat & CE_OVERRUN) {
16682: p->line_stat_err |= 0x02;
16683: }
16684: LeaveCriticalSection(&q->csLineStat);
16685:
16686: if(comStat.cbInQue != 0) {
16687: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 16688: DWORD dwRecv = 0;
16689: if(p->recv_buffer != NULL) {
16690: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
16691: }
1.1.1.25 root 16692: LeaveCriticalSection(&q->csRecvData);
16693:
16694: if(dwRecv != 0) {
16695: DWORD dwRead = 0;
16696: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
16697: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 16698: if(p->recv_buffer != NULL) {
16699: for(int i = 0; i < dwRead; i++) {
16700: p->recv_buffer->write(bytBuffer[i]);
16701: }
1.1.1.25 root 16702: }
16703: LeaveCriticalSection(&q->csRecvData);
16704: }
16705: }
16706: }
16707: }
16708: Sleep(10);
16709: }
16710: CloseHandle(hComm);
16711: }
16712: return 0;
16713: }
16714:
1.1.1.8 root 16715: // cmos
16716:
16717: void cmos_init()
16718: {
16719: memset(cmos, 0, sizeof(cmos));
16720: cmos_addr = 0;
1.1 root 16721:
1.1.1.8 root 16722: // from DOSBox
16723: cmos_write(0x0a, 0x26);
16724: cmos_write(0x0b, 0x02);
16725: cmos_write(0x0d, 0x80);
1.1 root 16726: }
16727:
1.1.1.8 root 16728: void cmos_write(int addr, UINT8 val)
1.1 root 16729: {
1.1.1.8 root 16730: cmos[addr & 0x7f] = val;
16731: }
16732:
16733: #define CMOS_GET_TIME() { \
16734: UINT32 cur_sec = timeGetTime() / 1000 ; \
16735: if(prev_sec != cur_sec) { \
16736: GetLocalTime(&time); \
16737: prev_sec = cur_sec; \
16738: } \
1.1 root 16739: }
1.1.1.8 root 16740: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 16741:
1.1.1.8 root 16742: UINT8 cmos_read(int addr)
1.1 root 16743: {
1.1.1.8 root 16744: static SYSTEMTIME time;
16745: static UINT32 prev_sec = 0;
1.1 root 16746:
1.1.1.8 root 16747: switch(addr & 0x7f) {
16748: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
16749: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
16750: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
16751: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
16752: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
16753: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
16754: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
16755: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
16756: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
16757: case 0x15: return((MEMORY_END >> 10) & 0xff);
16758: case 0x16: return((MEMORY_END >> 18) & 0xff);
16759: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
16760: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
16761: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
16762: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
16763: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 16764: }
1.1.1.8 root 16765: return(cmos[addr & 0x7f]);
1.1 root 16766: }
16767:
1.1.1.7 root 16768: // kbd (a20)
16769:
16770: void kbd_init()
16771: {
1.1.1.8 root 16772: kbd_data = kbd_command = 0;
1.1.1.7 root 16773: kbd_status = 0x18;
16774: }
16775:
16776: UINT8 kbd_read_data()
16777: {
1.1.1.8 root 16778: kbd_status &= ~1;
1.1.1.7 root 16779: return(kbd_data);
16780: }
16781:
16782: void kbd_write_data(UINT8 val)
16783: {
16784: switch(kbd_command) {
16785: case 0xd1:
16786: i386_set_a20_line((val >> 1) & 1);
16787: break;
16788: }
16789: kbd_command = 0;
1.1.1.8 root 16790: kbd_status &= ~8;
1.1.1.7 root 16791: }
16792:
16793: UINT8 kbd_read_status()
16794: {
16795: return(kbd_status);
16796: }
16797:
16798: void kbd_write_command(UINT8 val)
16799: {
16800: switch(val) {
16801: case 0xd0:
16802: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 16803: kbd_status |= 1;
1.1.1.7 root 16804: break;
16805: case 0xdd:
16806: i386_set_a20_line(0);
16807: break;
16808: case 0xdf:
16809: i386_set_a20_line(1);
16810: break;
1.1.1.26 root 16811: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
16812: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 16813: if(!(val & 1)) {
1.1.1.8 root 16814: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 16815: // reset pic
16816: pic_init();
16817: pic[0].irr = pic[1].irr = 0x00;
16818: pic[0].imr = pic[1].imr = 0xff;
16819: }
16820: CPU_RESET_CALL(CPU_MODEL);
16821: i386_jmp_far(0x40, 0x67);
16822: }
16823: i386_set_a20_line((val >> 1) & 1);
16824: break;
16825: }
16826: kbd_command = val;
1.1.1.8 root 16827: kbd_status |= 8;
1.1.1.7 root 16828: }
16829:
1.1.1.9 root 16830: // vga
16831:
16832: UINT8 vga_read_status()
16833: {
16834: // 60hz
16835: static const int period[3] = {16, 17, 17};
16836: static int index = 0;
16837: UINT32 time = timeGetTime() % period[index];
16838:
16839: index = (index + 1) % 3;
1.1.1.14 root 16840: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 16841: }
16842:
1.1 root 16843: // i/o bus
16844:
1.1.1.29 root 16845: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
16846: //#define SW1US_PATCH
16847:
1.1.1.25 root 16848: UINT8 read_io_byte(offs_t addr)
1.1.1.33 root 16849: #ifdef USE_DEBUGGER
1.1.1.25 root 16850: {
1.1.1.33 root 16851: if(now_debugging) {
16852: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
16853: if(in_break_point.table[i].status == 1) {
16854: if(addr == in_break_point.table[i].addr) {
16855: in_break_point.hit = i + 1;
16856: now_suspended = true;
16857: break;
16858: }
16859: }
16860: }
1.1.1.25 root 16861: }
1.1.1.33 root 16862: return(debugger_read_io_byte(addr));
1.1.1.25 root 16863: }
1.1.1.33 root 16864: UINT8 debugger_read_io_byte(offs_t addr)
1.1.1.25 root 16865: #endif
1.1 root 16866: {
1.1.1.33 root 16867: UINT8 val = 0xff;
16868:
1.1 root 16869: switch(addr) {
1.1.1.29 root 16870: #ifdef SW1US_PATCH
16871: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
16872: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
1.1.1.33 root 16873: val = sio_read(0, addr - 1);
16874: break;
1.1.1.29 root 16875: #else
1.1.1.25 root 16876: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
16877: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1.1.1.33 root 16878: val = dma_read(0, addr);
16879: break;
1.1.1.29 root 16880: #endif
1.1.1.25 root 16881: case 0x20: case 0x21:
1.1.1.33 root 16882: val = pic_read(0, addr);
16883: break;
1.1.1.25 root 16884: case 0x40: case 0x41: case 0x42: case 0x43:
1.1.1.33 root 16885: val = pit_read(addr & 0x03);
16886: break;
1.1.1.7 root 16887: case 0x60:
1.1.1.33 root 16888: val = kbd_read_data();
16889: break;
1.1.1.9 root 16890: case 0x61:
1.1.1.33 root 16891: val = system_port;
16892: break;
1.1.1.7 root 16893: case 0x64:
1.1.1.33 root 16894: val = kbd_read_status();
16895: break;
1.1 root 16896: case 0x71:
1.1.1.33 root 16897: val = cmos_read(cmos_addr);
16898: break;
1.1.1.25 root 16899: case 0x81:
1.1.1.33 root 16900: val = dma_page_read(0, 2);
16901: break;
1.1.1.25 root 16902: case 0x82:
1.1.1.33 root 16903: val = dma_page_read(0, 3);
16904: break;
1.1.1.25 root 16905: case 0x83:
1.1.1.33 root 16906: val = dma_page_read(0, 1);
16907: break;
1.1.1.25 root 16908: case 0x87:
1.1.1.33 root 16909: val = dma_page_read(0, 0);
16910: break;
1.1.1.25 root 16911: case 0x89:
1.1.1.33 root 16912: val = dma_page_read(1, 2);
16913: break;
1.1.1.25 root 16914: case 0x8a:
1.1.1.33 root 16915: val = dma_page_read(1, 3);
16916: break;
1.1.1.25 root 16917: case 0x8b:
1.1.1.33 root 16918: val = dma_page_read(1, 1);
16919: break;
1.1.1.25 root 16920: case 0x8f:
1.1.1.33 root 16921: val = dma_page_read(1, 0);
16922: break;
1.1 root 16923: case 0x92:
1.1.1.33 root 16924: val = (m_a20_mask >> 19) & 2;
16925: break;
1.1.1.25 root 16926: case 0xa0: case 0xa1:
1.1.1.33 root 16927: val = pic_read(1, addr);
16928: break;
1.1.1.25 root 16929: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
16930: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.33 root 16931: val = dma_read(1, (addr - 0xc0) >> 1);
16932: break;
1.1.1.26 root 16933: // case 0x278: case 0x279: case 0x27a:
1.1.1.33 root 16934: // val = pio_read(1, addr);
16935: // break;
1.1.1.29 root 16936: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
1.1.1.33 root 16937: val = sio_read(3, addr);
16938: break;
1.1.1.25 root 16939: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
1.1.1.33 root 16940: val = sio_read(1, addr);
16941: break;
1.1.1.25 root 16942: case 0x378: case 0x379: case 0x37a:
1.1.1.33 root 16943: val = pio_read(0, addr);
16944: break;
1.1.1.25 root 16945: case 0x3ba: case 0x3da:
1.1.1.33 root 16946: val = vga_read_status();
16947: break;
1.1.1.29 root 16948: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
1.1.1.33 root 16949: val = sio_read(2, addr);
16950: break;
1.1.1.25 root 16951: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
1.1.1.33 root 16952: val = sio_read(0, addr);
16953: break;
1.1 root 16954: default:
1.1.1.33 root 16955: // fatalerror("unknown inb %4x\n", addr);
1.1 root 16956: break;
16957: }
1.1.1.33 root 16958: #ifdef ENABLE_DEBUG_IOPORT
16959: if(fp_debug_log != NULL) {
16960: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
16961: }
16962: #endif
16963: return(val);
1.1 root 16964: }
16965:
16966: UINT16 read_io_word(offs_t addr)
16967: {
16968: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
16969: }
16970:
1.1.1.33 root 16971: #ifdef USE_DEBUGGER
16972: UINT16 debugger_read_io_word(offs_t addr)
16973: {
16974: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
16975: }
16976: #endif
16977:
1.1 root 16978: UINT32 read_io_dword(offs_t addr)
16979: {
16980: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
16981: }
16982:
1.1.1.33 root 16983: #ifdef USE_DEBUGGER
16984: UINT32 debugger_read_io_dword(offs_t addr)
16985: {
16986: 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));
16987: }
16988: #endif
16989:
1.1 root 16990: void write_io_byte(offs_t addr, UINT8 val)
1.1.1.33 root 16991: #ifdef USE_DEBUGGER
16992: {
16993: if(now_debugging) {
16994: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
16995: if(out_break_point.table[i].status == 1) {
16996: if(addr == out_break_point.table[i].addr) {
16997: out_break_point.hit = i + 1;
16998: now_suspended = true;
16999: break;
17000: }
17001: }
17002: }
17003: }
17004: debugger_write_io_byte(addr, val);
17005: }
17006: void debugger_write_io_byte(offs_t addr, UINT8 val)
17007: #endif
1.1 root 17008: {
1.1.1.25 root 17009: #ifdef ENABLE_DEBUG_IOPORT
1.1.1.33 root 17010: if(fp_debug_log != NULL) {
17011: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
1.1.1.25 root 17012: }
17013: #endif
1.1 root 17014: switch(addr) {
1.1.1.29 root 17015: #ifdef SW1US_PATCH
17016: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
17017: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
17018: sio_write(0, addr - 1, val);
17019: break;
17020: #else
1.1.1.25 root 17021: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
17022: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
17023: dma_write(0, addr, val);
17024: break;
1.1.1.29 root 17025: #endif
1.1.1.25 root 17026: case 0x20: case 0x21:
1.1 root 17027: pic_write(0, addr, val);
17028: break;
1.1.1.25 root 17029: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 17030: pit_write(addr & 0x03, val);
17031: break;
1.1.1.7 root 17032: case 0x60:
17033: kbd_write_data(val);
17034: break;
1.1.1.9 root 17035: case 0x61:
17036: if((system_port & 3) != 3 && (val & 3) == 3) {
17037: // beep on
17038: // MessageBeep(-1);
17039: } else if((system_port & 3) == 3 && (val & 3) != 3) {
17040: // beep off
17041: }
17042: system_port = val;
17043: break;
1.1 root 17044: case 0x64:
1.1.1.7 root 17045: kbd_write_command(val);
1.1 root 17046: break;
17047: case 0x70:
17048: cmos_addr = val;
17049: break;
17050: case 0x71:
1.1.1.8 root 17051: cmos_write(cmos_addr, val);
1.1 root 17052: break;
1.1.1.25 root 17053: case 0x81:
17054: dma_page_write(0, 2, val);
17055: case 0x82:
17056: dma_page_write(0, 3, val);
17057: case 0x83:
17058: dma_page_write(0, 1, val);
17059: case 0x87:
17060: dma_page_write(0, 0, val);
17061: case 0x89:
17062: dma_page_write(1, 2, val);
17063: case 0x8a:
17064: dma_page_write(1, 3, val);
17065: case 0x8b:
17066: dma_page_write(1, 1, val);
17067: case 0x8f:
17068: dma_page_write(1, 0, val);
1.1 root 17069: case 0x92:
1.1.1.7 root 17070: i386_set_a20_line((val >> 1) & 1);
1.1 root 17071: break;
1.1.1.25 root 17072: case 0xa0: case 0xa1:
1.1 root 17073: pic_write(1, addr, val);
17074: break;
1.1.1.25 root 17075: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
17076: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 17077: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 17078: break;
1.1.1.35! root 17079: #ifdef USE_SERVICE_THREAD
! 17080: case 0xf7:
! 17081: // dummy i/o for BIOS/DOS service
! 17082: finish_service_loop();
! 17083: break;
! 17084: #endif
1.1.1.26 root 17085: // case 0x278: case 0x279: case 0x27a:
17086: // pio_write(1, addr, val);
17087: // break;
1.1.1.29 root 17088: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
17089: sio_write(3, addr, val);
17090: break;
1.1.1.25 root 17091: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
17092: sio_write(1, addr, val);
17093: break;
17094: case 0x378: case 0x379: case 0x37a:
17095: pio_write(0, addr, val);
17096: break;
1.1.1.29 root 17097: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
17098: sio_write(2, addr, val);
17099: break;
1.1.1.25 root 17100: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
17101: sio_write(0, addr, val);
17102: break;
1.1 root 17103: default:
1.1.1.33 root 17104: // fatalerror("unknown outb %4x,%2x\n", addr, val);
1.1 root 17105: break;
17106: }
17107: }
17108:
17109: void write_io_word(offs_t addr, UINT16 val)
17110: {
17111: write_io_byte(addr + 0, (val >> 0) & 0xff);
17112: write_io_byte(addr + 1, (val >> 8) & 0xff);
17113: }
17114:
1.1.1.33 root 17115: #ifdef USE_DEBUGGER
17116: void debugger_write_io_word(offs_t addr, UINT16 val)
17117: {
17118: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
17119: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
17120: }
17121: #endif
17122:
1.1 root 17123: void write_io_dword(offs_t addr, UINT32 val)
17124: {
17125: write_io_byte(addr + 0, (val >> 0) & 0xff);
17126: write_io_byte(addr + 1, (val >> 8) & 0xff);
17127: write_io_byte(addr + 2, (val >> 16) & 0xff);
17128: write_io_byte(addr + 3, (val >> 24) & 0xff);
17129: }
1.1.1.33 root 17130:
17131: #ifdef USE_DEBUGGER
17132: void debugger_write_io_dword(offs_t addr, UINT32 val)
17133: {
17134: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
17135: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
17136: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
17137: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
17138: }
17139: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.