|
|
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.1.36! root 3233: // IME may be on and it may causes screen scroll up and cursor position change
! 3234: cursor_moved = true;
1.1 root 3235: }
3236: }
3237: }
3238: }
1.1.1.35 root 3239: #ifdef USE_SERVICE_THREAD
3240: LeaveCriticalSection(&input_crit_sect);
3241: #endif
1.1.1.24 root 3242: return(result);
1.1.1.8 root 3243: }
3244:
1.1.1.14 root 3245: bool update_key_buffer()
1.1.1.8 root 3246: {
1.1.1.35 root 3247: if(update_console_input()) {
3248: return(true);
3249: }
3250: if(key_buf_char != NULL && key_buf_scan != NULL) {
3251: #ifdef USE_SERVICE_THREAD
3252: EnterCriticalSection(&key_buf_crit_sect);
3253: #endif
3254: bool empty = key_buf_char->empty();
3255: #ifdef USE_SERVICE_THREAD
3256: LeaveCriticalSection(&key_buf_crit_sect);
3257: #endif
3258: if(!empty) return(true);
3259: }
3260: return(false);
1.1.1.8 root 3261: }
3262:
1.1.1.20 root 3263: /* ----------------------------------------------------------------------------
3264: MS-DOS virtual machine
3265: ---------------------------------------------------------------------------- */
3266:
1.1.1.32 root 3267: static const struct {
1.1.1.33 root 3268: char *name;
3269: DWORD lcid;
3270: char *std;
3271: char *dlt;
3272: } tz_table[] = {
3273: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
3274: // 0 GMT Greenwich Mean Time GMT0
3275: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
3276: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
3277: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
3278: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
3279: // 2 FST FDT Fernando De Noronha Std FST2FDT
3280: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3281: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3282: // 3 BST Brazil Standard Time BST3
3283: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
3284: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
3285: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
3286: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
3287: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
3288: // 3 GST Greenland Standard Time GST3
3289: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
3290: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
3291: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
3292: // 4 AST ADT Atlantic Standard Time AST4ADT
3293: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
3294: // 4 WST WDT Western Standard (Brazil) WST4WDT
3295: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
3296: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
3297: // 5 EST EDT Eastern Standard Time EST5EDT
3298: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
3299: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
3300: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
3301: // 5 CST CDT Chile Standard Time CST5CDT
3302: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
3303: // 5 AST ADT Acre Standard Time AST5ADT
3304: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
3305: // 5 CST CDT Cuba Standard Time CST5CDT
3306: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
3307: // 6 CST CDT Central Standard Time CST6CDT
3308: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
3309: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
3310: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
3311: // 6 EST EDT Easter Island Standard EST6EDT
3312: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
3313: // 7 MST MDT Mountain Standard Time MST7MDT
3314: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
3315: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
3316: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
3317: // 8 PST PDT Pacific Standard Time PST8PDT
3318: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
3319: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
3320: // 9 AKS AKD Alaska Standard Time AKS9AKD
3321: // 9 YST YDT Yukon Standard Time YST9YST
3322: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
3323: // 10 HST HDT Hawaii Standard Time HST10HDT
3324: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
3325: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
3326: // 11 SST Samoa Standard Time SST11
3327: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
3328: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
3329: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
3330: // -10 GST Guam Standard Time GST-10
3331: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
3332: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
3333: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
3334: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
3335: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
3336: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
3337: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
3338: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
3339: // -9 JST Japan Standard Time JST-9
3340: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
3341: // -9 KST KDT Korean Standard Time KST-9KDT
3342: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
3343: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
3344: // -8 HKT Hong Kong Time HKT-8
3345: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
3346: // -8 CCT China Coast Time CCT-8
3347: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
3348: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
3349: // -8 SST Singapore Standard Time SST-8
3350: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
3351: // -8 WAS WAD Western Australian Standard WAS-8WAD
3352: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
3353: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
3354: // -7:30 JT Java Standard Time JST-7:30
3355: // -7 NST North Sumatra Time NST-7
3356: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
3357: // -5:30 IST Indian Standard Time IST-5:30
3358: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
3359: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
3360: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
3361: // -3 MSK MSD Moscow Winter Time MSK-3MSD
3362: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
3363: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
3364: // -2 EET Eastern Europe Time EET-2
3365: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
3366: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
3367: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
3368: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
3369: // -2 IST IDT Israel Standard Time IST-2IDT
3370: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
3371: // -1 MEZ MES Middle European Time MEZ-1MES
3372: // -1 SWT SST Swedish Winter Time SWT-1SST
3373: // -1 FWT FST French Winter Time FWT-1FST
3374: // -1 CET CES Central European Time CET-1CES
3375: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
3376: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
3377: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
3378: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
3379: // -1 WAT West African Time WAT-1
3380: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
3381: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
3382: // 0 UTC Universal Coordinated Time UTC0
3383: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
3384: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
3385: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
3386: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
3387: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
3388: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
3389: };
3390:
3391: static const struct {
1.1.1.32 root 3392: UINT16 code;
3393: char *message_english;
3394: char *message_japanese;
3395: } standard_error_table[] = {
3396: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3397: {0x02, "File not found", "�t�@�C����������܂���."},
3398: {0x03, "Path not found", "�p�X��������܂���."},
3399: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3400: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3401: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3402: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3403: {0x08, "Insufficient memory", "������������܂���."},
3404: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3405: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3406: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3407: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3408: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3409: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3410: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3411: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3412: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3413: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3414: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3415: {0x15, "Not ready", "�������ł��Ă��܂���."},
3416: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3417: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3418: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3419: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3420: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3421: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3422: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3423: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3424: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3425: {0x1F, "General failure", "�G���[�ł�."},
3426: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3427: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3428: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3429: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3430: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3431: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3432: {0x26, "Out of input", "���͂��I���܂���."},
3433: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3434: /*
3435: {0x32, "Network request not supported", NULL},
3436: {0x33, "Remote computer not listening", NULL},
3437: {0x34, "Duplicate name on network", NULL},
3438: {0x35, "Network name not found", NULL},
3439: {0x36, "Network busy", NULL},
3440: {0x37, "Network device no longer exists", NULL},
3441: {0x38, "Network BIOS command limit exceeded", NULL},
3442: {0x39, "Network adapter hardware error", NULL},
3443: {0x3A, "Incorrect response from network", NULL},
3444: {0x3B, "Unexpected network error", NULL},
3445: {0x3C, "Incompatible remote adapter", NULL},
3446: {0x3D, "Print queue full", NULL},
3447: {0x3E, "Queue not full", NULL},
3448: {0x3F, "Not enough space to print file", NULL},
3449: {0x40, "Network name was deleted", NULL},
3450: {0x41, "Network: Access denied", NULL},
3451: {0x42, "Network device type incorrect", NULL},
3452: {0x43, "Network name not found", NULL},
3453: {0x44, "Network name limit exceeded", NULL},
3454: {0x45, "Network BIOS session limit exceeded", NULL},
3455: {0x46, "Temporarily paused", NULL},
3456: {0x47, "Network request not accepted", NULL},
3457: {0x48, "Network print/disk redirection paused", NULL},
3458: {0x49, "Network software not installed", NULL},
3459: {0x4A, "Unexpected adapter close", NULL},
3460: */
3461: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
1.1.1.33 root 3462: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
1.1.1.32 root 3463: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3464: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3465: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3466: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3467: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3468: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3469: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3470: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
3471: /*
3472: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3473: {0x65, "Not ready", "�������ł��Ă��܂���."},
3474: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3475: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3476: {0x68, "Door open", "���o�[���܂��Ă��܂���."
3477: */
3478: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3479: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3480: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3481: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3482: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3483: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3484: };
3485:
3486: static const struct {
3487: UINT16 code;
3488: char *message_english;
3489: char *message_japanese;
3490: } param_error_table[] = {
3491: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3492: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3493: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3494: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3495: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3496: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3497: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3498: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3499: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3500: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3501: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3502: };
3503:
3504: static const struct {
3505: UINT16 code;
3506: char *message_english;
3507: char *message_japanese;
3508: } critical_error_table[] = {
3509: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3510: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3511: {0x02, "Not ready", "�������ł��Ă��܂���."},
3512: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3513: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3514: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3515: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3516: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3517: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3518: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3519: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3520: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3521: {0x0C, "General failure", "�G���[�ł�."},
3522: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3523: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3524: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3525: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3526: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3527: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3528: {0x13, "Out of input", "���͂��I���܂���."},
3529: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3530: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3531: };
3532:
1.1.1.20 root 3533: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3534: int msdos_psp_get_file_table(int fd, int psp_seg);
3535: void msdos_putch(UINT8 data);
1.1.1.35 root 3536: #ifdef USE_SERVICE_THREAD
3537: void msdos_putch_tmp(UINT8 data);
3538: #endif
1.1.1.20 root 3539:
1.1 root 3540: // process info
3541:
3542: process_t *msdos_process_info_create(UINT16 psp_seg)
3543: {
3544: for(int i = 0; i < MAX_PROCESS; i++) {
3545: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3546: memset(&process[i], 0, sizeof(process_t));
3547: process[i].psp = psp_seg;
3548: return(&process[i]);
3549: }
3550: }
3551: fatalerror("too many processes\n");
3552: return(NULL);
3553: }
3554:
1.1.1.33 root 3555: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error)
1.1 root 3556: {
3557: for(int i = 0; i < MAX_PROCESS; i++) {
3558: if(process[i].psp == psp_seg) {
3559: return(&process[i]);
3560: }
3561: }
1.1.1.33 root 3562: if(show_error) {
3563: fatalerror("invalid psp address\n");
3564: }
1.1 root 3565: return(NULL);
3566: }
3567:
1.1.1.33 root 3568: process_t *msdos_process_info_get(UINT16 psp_seg)
3569: {
3570: return(msdos_process_info_get(psp_seg, true));
3571: }
3572:
1.1.1.23 root 3573: void msdos_sda_update(int psp_seg)
3574: {
3575: sda_t *sda = (sda_t *)(mem + SDA_TOP);
3576:
3577: for(int i = 0; i < MAX_PROCESS; i++) {
3578: if(process[i].psp == psp_seg) {
3579: sda->switchar = process[i].switchar;
3580: sda->current_dta.w.l = process[i].dta.w.l;
3581: sda->current_dta.w.h = process[i].dta.w.h;
3582: sda->current_psp = process[i].psp;
3583: break;
3584: }
3585: }
3586: sda->malloc_strategy = malloc_strategy;
3587: sda->return_code = retval;
3588: sda->current_drive = _getdrive();
3589: }
3590:
1.1.1.13 root 3591: // dta info
3592:
3593: void msdos_dta_info_init()
3594: {
1.1.1.14 root 3595: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 3596: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3597: }
3598: }
3599:
3600: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
3601: {
3602: dtainfo_t *free_dta = NULL;
1.1.1.14 root 3603: for(int i = 0; i < MAX_DTAINFO; i++) {
3604: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
3605: if(free_dta == NULL) {
1.1.1.13 root 3606: free_dta = &dtalist[i];
3607: }
1.1.1.14 root 3608: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 3609: return(&dtalist[i]);
3610: }
3611: }
1.1.1.14 root 3612: if(free_dta) {
1.1.1.13 root 3613: free_dta->psp = psp_seg;
3614: free_dta->dta = dta_laddr;
3615: return(free_dta);
3616: }
3617: fatalerror("too many dta\n");
3618: return(NULL);
3619: }
3620:
3621: void msdos_dta_info_free(UINT16 psp_seg)
3622: {
1.1.1.14 root 3623: for(int i = 0; i < MAX_DTAINFO; i++) {
3624: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 3625: FindClose(dtalist[i].find_handle);
3626: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3627: }
3628: }
3629: }
3630:
1.1 root 3631: void msdos_cds_update(int drv)
3632: {
3633: cds_t *cds = (cds_t *)(mem + CDS_TOP);
3634:
3635: memset(mem + CDS_TOP, 0, CDS_SIZE);
3636: sprintf(cds->path_name, "%c:\\", 'A' + drv);
3637: cds->drive_attrib = 0x4000; // physical drive
3638: cds->physical_drive_number = drv;
3639: }
3640:
1.1.1.17 root 3641: // nls information tables
3642:
3643: // uppercase table (func 6502h)
3644: void msdos_upper_table_update()
3645: {
3646: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3647: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3648: UINT8 c[4];
1.1.1.33 root 3649: *(UINT32 *)c = 0; // reset internal conversion state
3650: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.17 root 3651: c[0] = 0x80 + i;
3652: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
3653: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3654: }
3655: }
3656:
1.1.1.23 root 3657: // lowercase table (func 6503h)
3658: void msdos_lower_table_update()
3659: {
3660: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
3661: for(unsigned i = 0; i < 0x80; ++i) {
3662: UINT8 c[4];
1.1.1.33 root 3663: *(UINT32 *)c = 0; // reset internal conversion state
3664: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.23 root 3665: c[0] = 0x80 + i;
3666: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
3667: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3668: }
3669: }
3670:
1.1.1.17 root 3671: // filename uppercase table (func 6504h)
3672: void msdos_filename_upper_table_init()
3673: {
3674: // depended on (file)system, not on active codepage
3675: // temporary solution: just filling data
3676: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3677: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3678: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
3679: }
3680: }
3681:
3682: // filaname terminator table (func 6505h)
3683: void msdos_filename_terminator_table_init()
3684: {
3685: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
3686: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
3687:
3688: data[2] = 1; // marker? (permissible character value)
3689: data[3] = 0x00; // 00h...FFh
3690: data[4] = 0xff;
3691: data[5] = 0; // marker? (excluded character)
3692: data[6] = 0x00; // 00h...20h
3693: data[7] = 0x20;
3694: data[8] = 2; // marker? (illegal characters for filename)
3695: data[9] = (UINT8)strlen(illegal_chars);
3696: memcpy(data + 10, illegal_chars, data[9]);
3697:
3698: // total length
3699: *(UINT16 *)data = (10 - 2) + data[9];
3700: }
3701:
3702: // collating table (func 6506h)
3703: void msdos_collating_table_update()
3704: {
3705: // temporary solution: just filling data
3706: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 3707: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 3708: mem[COLLATING_TABLE_TOP + 2 + i] = i;
3709: }
3710: }
3711:
1.1 root 3712: // dbcs
3713:
3714: void msdos_dbcs_table_update()
3715: {
3716: UINT8 dbcs_data[DBCS_SIZE];
3717: memset(dbcs_data, 0, sizeof(dbcs_data));
3718:
3719: CPINFO info;
3720: GetCPInfo(active_code_page, &info);
3721:
3722: if(info.MaxCharSize != 1) {
3723: for(int i = 0;; i += 2) {
3724: UINT8 lo = info.LeadByte[i + 0];
3725: UINT8 hi = info.LeadByte[i + 1];
3726: dbcs_data[2 + i + 0] = lo;
3727: dbcs_data[2 + i + 1] = hi;
3728: if(lo == 0 && hi == 0) {
3729: dbcs_data[0] = i + 2;
3730: break;
3731: }
3732: }
3733: } else {
3734: dbcs_data[0] = 2; // ???
3735: }
3736: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
3737: }
3738:
1.1.1.17 root 3739: void msdos_dbcs_table_finish()
3740: {
1.1.1.32 root 3741: if(system_code_page != _getmbcp()) {
1.1.1.17 root 3742: _setmbcp(system_code_page);
3743: }
1.1.1.32 root 3744: if(console_code_page != GetConsoleCP()) {
3745: SetConsoleCP(console_code_page);
3746: SetConsoleOutputCP(console_code_page);
3747: }
1.1.1.17 root 3748: }
3749:
3750: void msdos_nls_tables_init()
1.1 root 3751: {
1.1.1.32 root 3752: active_code_page = console_code_page = GetConsoleCP();
3753: system_code_page = _getmbcp();
3754:
3755: if(active_code_page != system_code_page) {
3756: if(_setmbcp(active_code_page) != 0) {
3757: active_code_page = system_code_page;
3758: }
3759: }
3760:
1.1.1.17 root 3761: msdos_upper_table_update();
1.1.1.23 root 3762: msdos_lower_table_update();
1.1.1.17 root 3763: msdos_filename_terminator_table_init();
3764: msdos_filename_upper_table_init();
3765: msdos_collating_table_update();
1.1 root 3766: msdos_dbcs_table_update();
3767: }
3768:
1.1.1.17 root 3769: void msdos_nls_tables_update()
1.1 root 3770: {
1.1.1.17 root 3771: msdos_dbcs_table_update();
3772: msdos_upper_table_update();
1.1.1.23 root 3773: msdos_lower_table_update();
3774: // msdos_collating_table_update();
1.1 root 3775: }
3776:
3777: int msdos_lead_byte_check(UINT8 code)
3778: {
3779: UINT8 *dbcs_table = mem + DBCS_TABLE;
3780:
3781: for(int i = 0;; i += 2) {
3782: UINT8 lo = dbcs_table[i + 0];
3783: UINT8 hi = dbcs_table[i + 1];
3784: if(lo == 0 && hi == 0) {
3785: break;
3786: }
3787: if(lo <= code && code <= hi) {
3788: return(1);
3789: }
3790: }
3791: return(0);
3792: }
3793:
1.1.1.20 root 3794: int msdos_ctrl_code_check(UINT8 code)
3795: {
1.1.1.22 root 3796: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 3797: }
3798:
1.1.1.36! root 3799: int msdos_kanji_2nd_byte_check(UINT8 *buf, int n)
! 3800: {
! 3801: int is_kanji_1st = 0;
! 3802: int is_kanji_2nd = 0;
! 3803:
! 3804: for(int p = 0;; p++) {
! 3805: if(is_kanji_1st) {
! 3806: is_kanji_1st = 0;
! 3807: is_kanji_2nd = 1;
! 3808: } else if(msdos_lead_byte_check(buf[p])) {
! 3809: is_kanji_1st = 1;
! 3810: }
! 3811: if(p == n) {
! 3812: return(is_kanji_2nd);
! 3813: }
! 3814: is_kanji_2nd = 0;
! 3815: }
! 3816: }
! 3817:
1.1 root 3818: // file control
3819:
1.1.1.14 root 3820: char *msdos_remove_double_quote(char *path)
3821: {
3822: static char tmp[MAX_PATH];
3823:
3824: memset(tmp, 0, sizeof(tmp));
3825: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
3826: memcpy(tmp, path + 1, strlen(path) - 2);
3827: } else {
3828: strcpy(tmp, path);
3829: }
3830: return(tmp);
3831: }
3832:
1.1.1.32 root 3833: char *msdos_remove_end_separator(char *path)
3834: {
3835: static char tmp[MAX_PATH];
3836:
3837: strcpy(tmp, path);
3838: int len = strlen(tmp);
3839: if(len > 3 && tmp[len - 1] == '\\') {
3840: tmp[len - 1] = '\0';
3841: }
3842: return(tmp);
3843: }
3844:
1.1.1.14 root 3845: char *msdos_combine_path(char *dir, const char *file)
3846: {
3847: static char tmp[MAX_PATH];
3848: char *tmp_dir = msdos_remove_double_quote(dir);
3849:
3850: if(strlen(tmp_dir) == 0) {
3851: strcpy(tmp, file);
3852: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
3853: sprintf(tmp, "%s%s", tmp_dir, file);
3854: } else {
3855: sprintf(tmp, "%s\\%s", tmp_dir, file);
3856: }
3857: return(tmp);
3858: }
3859:
1.1 root 3860: char *msdos_trimmed_path(char *path, int lfn)
3861: {
3862: static char tmp[MAX_PATH];
3863:
3864: if(lfn) {
3865: strcpy(tmp, path);
3866: } else {
3867: // remove space in the path
3868: char *src = path, *dst = tmp;
3869:
3870: while(*src != '\0') {
3871: if(msdos_lead_byte_check(*src)) {
3872: *dst++ = *src++;
3873: *dst++ = *src++;
3874: } else if(*src != ' ') {
3875: *dst++ = *src++;
3876: } else {
3877: src++; // skip space
3878: }
3879: }
3880: *dst = '\0';
3881: }
1.1.1.14 root 3882: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
3883: // redirect C:\COMMAND.COM to comspec_path
3884: strcpy(tmp, comspec_path);
3885: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
3886: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
3887: static int root_drive_protected = -1;
3888: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
3889: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
3890:
3891: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
3892: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
3893: strcpy(name, name_temp);
3894: name_temp[0] = '\0';
3895:
3896: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
3897: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
3898: if(root_drive_protected == -1) {
3899: FILE *fp = NULL;
3900:
3901: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
3902: root_drive_protected = 1;
3903: try {
3904: if((fp = fopen(temp, "w")) != NULL) {
3905: if(fprintf(fp, "TEST") == 4) {
3906: root_drive_protected = 0;
3907: }
3908: }
3909: } catch(...) {
3910: }
3911: if(fp != NULL) {
3912: fclose(fp);
3913: }
3914: if(_access(temp, 0) == 0) {
3915: remove(temp);
3916: }
3917: }
3918: if(root_drive_protected == 1) {
3919: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
3920: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
3921: strcpy(tmp, msdos_combine_path(temp, name));
3922: }
3923: }
3924: }
3925: }
3926: }
1.1 root 3927: return(tmp);
3928: }
3929:
1.1.1.28 root 3930: char *msdos_get_multiple_short_path(char *src)
3931: {
1.1.1.32 root 3932: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 3933: static char env_path[ENV_SIZE];
3934: char tmp[ENV_SIZE], *token;
3935:
3936: memset(env_path, 0, sizeof(env_path));
3937: strcpy(tmp, src);
3938: token = my_strtok(tmp, ";");
3939:
3940: while(token != NULL) {
3941: if(token[0] != '\0') {
3942: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.32 root 3943: if(path != NULL && strlen(path) != 0) {
3944: if(env_path[0] != '\0') {
3945: strcat(env_path, ";");
3946: }
1.1.1.28 root 3947: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32 root 3948: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 3949: } else {
3950: my_strupr(short_path);
1.1.1.32 root 3951: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 3952: }
3953: }
3954: }
3955: token = my_strtok(NULL, ";");
3956: }
3957: return(env_path);
3958: }
3959:
1.1 root 3960: bool match(char *text, char *pattern)
3961: {
1.1.1.24 root 3962: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 3963: switch(*pattern) {
1.1 root 3964: case '\0':
3965: return !*text;
3966: case '*':
1.1.1.14 root 3967: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 3968: case '?':
3969: return *text && match(text + 1, pattern + 1);
3970: default:
3971: return (*text == *pattern) && match(text + 1, pattern + 1);
3972: }
3973: }
3974:
3975: bool msdos_match_volume_label(char *path, char *volume)
3976: {
3977: char *p;
3978:
1.1.1.14 root 3979: if(!*volume) {
3980: return false;
3981: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 3982: return msdos_match_volume_label(p + 1, volume);
3983: } else if((p = my_strchr(path, '\\')) != NULL) {
3984: return msdos_match_volume_label(p + 1, volume);
3985: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 3986: char tmp[MAX_PATH];
3987: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
3988: return match(volume, tmp);
1.1 root 3989: } else {
3990: return match(volume, path);
3991: }
3992: }
3993:
3994: char *msdos_fcb_path(fcb_t *fcb)
3995: {
3996: static char tmp[MAX_PATH];
3997: char name[9], ext[4];
3998:
3999: memset(name, 0, sizeof(name));
4000: memcpy(name, fcb->file_name, 8);
4001: strcpy(name, msdos_trimmed_path(name, 0));
4002:
4003: memset(ext, 0, sizeof(ext));
4004: memcpy(ext, fcb->file_name + 8, 3);
4005: strcpy(ext, msdos_trimmed_path(ext, 0));
4006:
4007: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
4008: strcpy(name, "*");
4009: }
4010: if(ext[0] == '\0') {
4011: strcpy(tmp, name);
4012: } else {
4013: if(strcmp(ext, "???") == 0) {
4014: strcpy(ext, "*");
4015: }
4016: sprintf(tmp, "%s.%s", name, ext);
4017: }
4018: return(tmp);
4019: }
4020:
4021: void msdos_set_fcb_path(fcb_t *fcb, char *path)
4022: {
4023: char *ext = my_strchr(path, '.');
4024:
4025: memset(fcb->file_name, 0x20, 8 + 3);
4026: if(ext != NULL && path[0] != '.') {
4027: *ext = '\0';
4028: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
4029: }
4030: memcpy(fcb->file_name, path, strlen(path));
4031: }
4032:
4033: char *msdos_short_path(char *path)
4034: {
4035: static char tmp[MAX_PATH];
4036:
1.1.1.24 root 4037: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
4038: strcpy(tmp, path);
4039: }
1.1 root 4040: my_strupr(tmp);
4041: return(tmp);
4042: }
4043:
1.1.1.13 root 4044: char *msdos_short_name(WIN32_FIND_DATA *fd)
4045: {
4046: static char tmp[MAX_PATH];
4047:
1.1.1.14 root 4048: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4049: strcpy(tmp, fd->cAlternateFileName);
4050: } else {
4051: strcpy(tmp, fd->cFileName);
4052: }
4053: my_strupr(tmp);
4054: return(tmp);
4055: }
4056:
1.1 root 4057: char *msdos_short_full_path(char *path)
4058: {
4059: static char tmp[MAX_PATH];
4060: char full[MAX_PATH], *name;
4061:
1.1.1.14 root 4062: // Full works with non-existent files, but Short does not
1.1 root 4063: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 4064: *tmp = '\0';
4065: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
4066: name[-1] = '\0';
4067: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
4068: if(len == 0) {
4069: strcpy(tmp, full);
4070: } else {
4071: tmp[len++] = '\\';
4072: strcpy(tmp + len, name);
4073: }
4074: }
1.1 root 4075: my_strupr(tmp);
4076: return(tmp);
4077: }
4078:
4079: char *msdos_short_full_dir(char *path)
4080: {
4081: static char tmp[MAX_PATH];
4082: char full[MAX_PATH], *name;
4083:
4084: GetFullPathName(path, MAX_PATH, full, &name);
4085: name[-1] = '\0';
1.1.1.24 root 4086: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
4087: strcpy(tmp, full);
4088: }
1.1 root 4089: my_strupr(tmp);
4090: return(tmp);
4091: }
4092:
4093: char *msdos_local_file_path(char *path, int lfn)
4094: {
4095: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 4096: #if 0
4097: // I have forgotten the reason of this routine... :-(
1.1 root 4098: if(_access(trimmed, 0) != 0) {
4099: process_t *process = msdos_process_info_get(current_psp);
4100: static char tmp[MAX_PATH];
4101:
4102: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
4103: if(_access(tmp, 0) == 0) {
4104: return(tmp);
4105: }
4106: }
1.1.1.14 root 4107: #endif
1.1 root 4108: return(trimmed);
4109: }
4110:
1.1.1.29 root 4111: bool msdos_is_device_path(char *path)
1.1.1.11 root 4112: {
4113: char full[MAX_PATH], *name;
4114:
1.1.1.24 root 4115: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4116: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4117: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4118: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4119: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4120: _stricmp(full, "\\\\.\\COM1") == 0 ||
4121: _stricmp(full, "\\\\.\\COM2") == 0 ||
4122: _stricmp(full, "\\\\.\\COM3") == 0 ||
4123: _stricmp(full, "\\\\.\\COM4") == 0 ||
4124: _stricmp(full, "\\\\.\\COM5") == 0 ||
4125: _stricmp(full, "\\\\.\\COM6") == 0 ||
4126: _stricmp(full, "\\\\.\\COM7") == 0 ||
4127: _stricmp(full, "\\\\.\\COM8") == 0 ||
4128: _stricmp(full, "\\\\.\\COM9") == 0 ||
4129: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4130: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4131: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4132: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4133: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4134: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4135: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4136: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4137: _stricmp(full, "\\\\.\\LPT9") == 0) {
4138: return(true);
4139: } else if(name != NULL) {
4140: if(_stricmp(name, "CLOCK$" ) == 0 ||
4141: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 4142: _stricmp(name, "EMMXXXX0") == 0 ||
4143: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 4144: return(true);
4145: }
4146: }
1.1.1.24 root 4147: }
4148: return(false);
1.1.1.11 root 4149: }
4150:
1.1.1.29 root 4151: bool msdos_is_con_path(char *path)
1.1.1.8 root 4152: {
1.1.1.14 root 4153: char full[MAX_PATH], *name;
1.1.1.8 root 4154:
1.1.1.24 root 4155: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4156: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 4157: }
4158: return(false);
4159: }
4160:
1.1.1.29 root 4161: int msdos_is_comm_path(char *path)
1.1.1.24 root 4162: {
4163: char full[MAX_PATH], *name;
4164:
4165: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4166: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4167: return(1);
4168: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4169: return(2);
4170: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4171: return(3);
4172: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4173: return(4);
1.1.1.24 root 4174: }
4175: }
1.1.1.29 root 4176: return(0);
4177: }
4178:
1.1.1.30 root 4179: int msdos_is_prn_path(char *path)
4180: {
4181: char full[MAX_PATH], *name;
4182:
4183: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4184: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4185: return(1);
4186: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4187: return(1);
4188: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4189: return(2);
4190: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4191: return(3);
4192: }
4193: }
4194: return(0);
4195: }
4196:
1.1.1.29 root 4197: char *msdos_create_comm_path(char *path, int port)
4198: {
4199: static char tmp[MAX_PATH];
4200: char *p = NULL;
4201:
4202: sprintf(tmp, "COM%d", port);
4203: if((p = strchr(path, ':')) != NULL) {
4204: strcat(tmp, p);
4205: }
4206: return(tmp);
1.1.1.24 root 4207: }
4208:
4209: bool msdos_is_existing_file(char *path)
4210: {
4211: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4212: WIN32_FIND_DATA FindData;
4213: HANDLE hFind;
4214:
4215: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
4216: FindClose(hFind);
4217: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
4218: }
4219: return(false);
1.1.1.8 root 4220: }
4221:
1.1.1.9 root 4222: char *msdos_search_command_com(char *command_path, char *env_path)
4223: {
4224: static char tmp[MAX_PATH];
1.1.1.28 root 4225: char path[ENV_SIZE], *file_name;
1.1.1.9 root 4226:
1.1.1.28 root 4227: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 4228: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
4229: sprintf(file_name, "COMMAND.COM");
4230: if(_access(tmp, 0) == 0) {
4231: return(tmp);
4232: }
4233: }
1.1.1.28 root 4234:
4235: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 4236: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
4237: sprintf(file_name, "COMMAND.COM");
4238: if(_access(tmp, 0) == 0) {
4239: return(tmp);
4240: }
4241: }
1.1.1.28 root 4242:
4243: // check if COMMAND.COM is in the current directory
1.1.1.9 root 4244: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4245: if(_access(tmp, 0) == 0) {
4246: return(tmp);
4247: }
4248: }
1.1.1.28 root 4249:
4250: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4251: strcpy(path, env_path);
4252: char *token = my_strtok(path, ";");
1.1.1.9 root 4253: while(token != NULL) {
1.1.1.14 root 4254: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 4255: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4256: if(_access(tmp, 0) == 0) {
4257: return(tmp);
4258: }
4259: }
4260: token = my_strtok(NULL, ";");
4261: }
4262: return(NULL);
4263: }
4264:
1.1.1.14 root 4265: int msdos_drive_number(const char *path)
1.1 root 4266: {
4267: char tmp[MAX_PATH], *name;
4268:
4269: GetFullPathName(path, MAX_PATH, tmp, &name);
4270: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4271: return(tmp[0] - 'a');
4272: } else {
4273: return(tmp[0] - 'A');
4274: }
4275: }
4276:
4277: char *msdos_volume_label(char *path)
4278: {
4279: static char tmp[MAX_PATH];
4280: char volume[] = "A:\\";
4281:
4282: if(path[1] == ':') {
4283: volume[0] = path[0];
4284: } else {
4285: volume[0] = 'A' + _getdrive() - 1;
4286: }
4287: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4288: memset(tmp, 0, sizeof(tmp));
4289: }
4290: return(tmp);
4291: }
4292:
4293: char *msdos_short_volume_label(char *label)
4294: {
4295: static char tmp[(8 + 1 + 3) + 1];
4296: char *src = label;
4297: int remain = strlen(label);
4298: char *dst_n = tmp;
4299: char *dst_e = tmp + 9;
4300:
4301: strcpy(tmp, " . ");
4302: for(int i = 0; i < 8 && remain > 0; i++) {
4303: if(msdos_lead_byte_check(*src)) {
4304: if(++i == 8) {
4305: break;
4306: }
4307: *dst_n++ = *src++;
4308: remain--;
4309: }
4310: *dst_n++ = *src++;
4311: remain--;
4312: }
4313: if(remain > 0) {
4314: for(int i = 0; i < 3 && remain > 0; i++) {
4315: if(msdos_lead_byte_check(*src)) {
4316: if(++i == 3) {
4317: break;
4318: }
4319: *dst_e++ = *src++;
4320: remain--;
4321: }
4322: *dst_e++ = *src++;
4323: remain--;
4324: }
4325: *dst_e = '\0';
4326: } else {
4327: *dst_n = '\0';
4328: }
4329: my_strupr(tmp);
4330: return(tmp);
4331: }
4332:
1.1.1.13 root 4333: errno_t msdos_maperr(unsigned long oserrno)
4334: {
4335: _doserrno = oserrno;
1.1.1.14 root 4336: switch(oserrno) {
1.1.1.13 root 4337: case ERROR_FILE_NOT_FOUND: // 2
4338: case ERROR_PATH_NOT_FOUND: // 3
4339: case ERROR_INVALID_DRIVE: // 15
4340: case ERROR_NO_MORE_FILES: // 18
4341: case ERROR_BAD_NETPATH: // 53
4342: case ERROR_BAD_NET_NAME: // 67
4343: case ERROR_BAD_PATHNAME: // 161
4344: case ERROR_FILENAME_EXCED_RANGE: // 206
4345: return ENOENT;
4346: case ERROR_TOO_MANY_OPEN_FILES: // 4
4347: return EMFILE;
4348: case ERROR_ACCESS_DENIED: // 5
4349: case ERROR_CURRENT_DIRECTORY: // 16
4350: case ERROR_NETWORK_ACCESS_DENIED: // 65
4351: case ERROR_CANNOT_MAKE: // 82
4352: case ERROR_FAIL_I24: // 83
4353: case ERROR_DRIVE_LOCKED: // 108
4354: case ERROR_SEEK_ON_DEVICE: // 132
4355: case ERROR_NOT_LOCKED: // 158
4356: case ERROR_LOCK_FAILED: // 167
4357: return EACCES;
4358: case ERROR_INVALID_HANDLE: // 6
4359: case ERROR_INVALID_TARGET_HANDLE: // 114
4360: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4361: return EBADF;
4362: case ERROR_ARENA_TRASHED: // 7
4363: case ERROR_NOT_ENOUGH_MEMORY: // 8
4364: case ERROR_INVALID_BLOCK: // 9
4365: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4366: return ENOMEM;
4367: case ERROR_BAD_ENVIRONMENT: // 10
4368: return E2BIG;
4369: case ERROR_BAD_FORMAT: // 11
4370: return ENOEXEC;
4371: case ERROR_NOT_SAME_DEVICE: // 17
4372: return EXDEV;
4373: case ERROR_FILE_EXISTS: // 80
4374: case ERROR_ALREADY_EXISTS: // 183
4375: return EEXIST;
4376: case ERROR_NO_PROC_SLOTS: // 89
4377: case ERROR_MAX_THRDS_REACHED: // 164
4378: case ERROR_NESTING_NOT_ALLOWED: // 215
4379: return EAGAIN;
4380: case ERROR_BROKEN_PIPE: // 109
4381: return EPIPE;
4382: case ERROR_DISK_FULL: // 112
4383: return ENOSPC;
4384: case ERROR_WAIT_NO_CHILDREN: // 128
4385: case ERROR_CHILD_NOT_COMPLETE: // 129
4386: return ECHILD;
4387: case ERROR_DIR_NOT_EMPTY: // 145
4388: return ENOTEMPTY;
4389: }
1.1.1.14 root 4390: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 4391: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4392: return EACCES;
4393: }
1.1.1.14 root 4394: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 4395: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4396: return ENOEXEC;
4397: }
4398: return EINVAL;
4399: }
4400:
4401: int msdos_open(const char *filename, int oflag)
4402: {
1.1.1.14 root 4403: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 4404: return _open(filename, oflag);
4405: }
1.1.1.14 root 4406:
4407: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 4408: DWORD disposition;
1.1.1.14 root 4409: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4410: default:
1.1.1.13 root 4411: case _O_EXCL:
4412: disposition = OPEN_EXISTING;
4413: break;
4414: case _O_CREAT:
4415: disposition = OPEN_ALWAYS;
4416: break;
4417: case _O_CREAT | _O_EXCL:
4418: case _O_CREAT | _O_TRUNC | _O_EXCL:
4419: disposition = CREATE_NEW;
4420: break;
4421: case _O_TRUNC:
4422: case _O_TRUNC | _O_EXCL:
4423: disposition = TRUNCATE_EXISTING;
4424: break;
4425: case _O_CREAT | _O_TRUNC:
4426: disposition = CREATE_ALWAYS;
4427: break;
4428: }
1.1.1.14 root 4429:
1.1.1.13 root 4430: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
4431: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4432: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4433: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4434: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4435: // Retry without FILE_WRITE_ATTRIBUTES.
4436: h = CreateFile(filename, GENERIC_READ,
4437: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4438: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4439: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4440: errno = msdos_maperr(GetLastError());
4441: return -1;
4442: }
4443: }
1.1.1.14 root 4444:
1.1.1.13 root 4445: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 4446: if(fd == -1) {
1.1.1.13 root 4447: CloseHandle(h);
4448: }
4449: return fd;
4450: }
4451:
1.1.1.14 root 4452: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 4453: {
4454: static int id = 0;
4455: char full[MAX_PATH], *name;
4456:
4457: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4458: strcpy(file_handler[fd].path, full);
4459: } else {
4460: strcpy(file_handler[fd].path, path);
4461: }
1.1.1.14 root 4462: // isatty makes no distinction between CON & NUL
4463: // GetFileSize fails on CON, succeeds on NUL
4464: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
4465: info = 0x8084;
4466: atty = 0;
4467: } else if(!atty && info == 0x80d3) {
4468: info = msdos_drive_number(".");
4469: }
1.1 root 4470: file_handler[fd].valid = 1;
4471: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
4472: file_handler[fd].atty = atty;
4473: file_handler[fd].mode = mode;
4474: file_handler[fd].info = info;
4475: file_handler[fd].psp = psp_seg;
1.1.1.21 root 4476:
4477: // init system file table
4478: if(fd < 20) {
4479: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
4480:
4481: memset(sft, 0, 0x3b);
4482:
4483: *(UINT16 *)(sft + 0x00) = 1;
4484: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
4485: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
4486: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
4487:
4488: if(!(file_handler[fd].info & 0x80)) {
4489: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
4490: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
4491:
4492: FILETIME time, local;
4493: HANDLE hHandle;
4494: WORD dos_date = 0, dos_time = 0;
4495: DWORD file_size = 0;
4496: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
4497: if(GetFileTime(hHandle, NULL, NULL, &time)) {
4498: FileTimeToLocalFileTime(&time, &local);
4499: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
4500: }
4501: file_size = GetFileSize(hHandle, NULL);
4502: }
4503: *(UINT16 *)(sft + 0x0d) = dos_time;
4504: *(UINT16 *)(sft + 0x0f) = dos_date;
4505: *(UINT32 *)(sft + 0x11) = file_size;
4506: }
4507:
4508: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
4509: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
4510: my_strupr(fname);
4511: my_strupr(ext);
4512: memset(sft + 0x20, 0x20, 11);
4513: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
4514: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
4515:
4516: *(UINT16 *)(sft + 0x31) = psp_seg;
4517: }
1.1 root 4518: }
4519:
4520: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
4521: {
4522: strcpy(file_handler[dst].path, file_handler[src].path);
4523: file_handler[dst].valid = 1;
4524: file_handler[dst].id = file_handler[src].id;
4525: file_handler[dst].atty = file_handler[src].atty;
4526: file_handler[dst].mode = file_handler[src].mode;
4527: file_handler[dst].info = file_handler[src].info;
4528: file_handler[dst].psp = psp_seg;
4529: }
4530:
1.1.1.20 root 4531: void msdos_file_handler_close(int fd)
1.1 root 4532: {
4533: file_handler[fd].valid = 0;
1.1.1.21 root 4534:
4535: if(fd < 20) {
4536: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
4537: }
1.1 root 4538: }
4539:
1.1.1.14 root 4540: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 4541: {
1.1.1.14 root 4542: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
4543: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
4544: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 4545: }
4546:
4547: // find file
4548:
4549: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
4550: {
4551: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4552: return(0); // search directory only !!!
4553: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
4554: return(0);
4555: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
4556: return(0);
4557: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4558: return(0);
4559: } else if((attribute & required_mask) != required_mask) {
4560: return(0);
4561: } else {
4562: return(1);
4563: }
4564: }
4565:
1.1.1.13 root 4566: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
4567: {
1.1.1.14 root 4568: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4569: return 1;
4570: }
4571: size_t len = strlen(fd->cFileName);
1.1.1.14 root 4572: if(len > 12) {
1.1.1.13 root 4573: return 0;
4574: }
4575: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 4576: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 4577: return 0;
4578: }
4579: return 1;
4580: }
4581:
1.1 root 4582: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
4583: {
4584: FILETIME local;
4585:
4586: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
4587: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
4588: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
4589:
4590: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
4591: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
4592: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
4593:
4594: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
4595: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
4596: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
4597: }
4598:
4599: // i/o
4600:
4601: void msdos_stdio_reopen()
4602: {
4603: if(!file_handler[0].valid) {
4604: _dup2(DUP_STDIN, 0);
4605: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
4606: }
4607: if(!file_handler[1].valid) {
4608: _dup2(DUP_STDOUT, 1);
4609: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
4610: }
4611: if(!file_handler[2].valid) {
4612: _dup2(DUP_STDERR, 2);
4613: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
4614: }
1.1.1.21 root 4615: if(!file_handler[3].valid) {
4616: _dup2(DUP_STDAUX, 3);
4617: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
4618: }
4619: if(!file_handler[4].valid) {
4620: _dup2(DUP_STDPRN, 4);
4621: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
4622: }
4623: for(int i = 0; i < 5; i++) {
4624: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
4625: msdos_psp_set_file_table(i, i, current_psp);
4626: }
4627: }
1.1 root 4628: }
4629:
4630: int msdos_kbhit()
4631: {
4632: msdos_stdio_reopen();
4633:
1.1.1.20 root 4634: process_t *process = msdos_process_info_get(current_psp);
4635: int fd = msdos_psp_get_file_table(0, current_psp);
4636:
4637: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4638: // stdin is redirected to file
1.1.1.20 root 4639: return(eof(fd) == 0);
1.1 root 4640: }
4641:
4642: // check keyboard status
1.1.1.35 root 4643: if(key_recv != 0) {
1.1 root 4644: return(1);
4645: }
1.1.1.35 root 4646: if(key_buf_char != NULL && key_buf_scan != NULL) {
4647: #ifdef USE_SERVICE_THREAD
4648: EnterCriticalSection(&key_buf_crit_sect);
4649: #endif
4650: bool empty = key_buf_char->empty();
4651: #ifdef USE_SERVICE_THREAD
4652: LeaveCriticalSection(&key_buf_crit_sect);
4653: #endif
4654: if(!empty) return(1);
4655: }
4656: return(_kbhit());
1.1 root 4657: }
4658:
4659: int msdos_getch_ex(int echo)
4660: {
4661: static char prev = 0;
4662:
4663: msdos_stdio_reopen();
4664:
1.1.1.20 root 4665: process_t *process = msdos_process_info_get(current_psp);
4666: int fd = msdos_psp_get_file_table(0, current_psp);
4667:
4668: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4669: // stdin is redirected to file
4670: retry:
4671: char data;
1.1.1.20 root 4672: if(_read(fd, &data, 1) == 1) {
1.1 root 4673: char tmp = data;
4674: if(data == 0x0a) {
4675: if(prev == 0x0d) {
4676: goto retry; // CRLF -> skip LF
4677: } else {
4678: data = 0x0d; // LF only -> CR
4679: }
4680: }
4681: prev = tmp;
4682: return(data);
4683: }
4684: return(EOF);
4685: }
4686:
4687: // input from console
1.1.1.5 root 4688: int key_char, key_scan;
1.1.1.33 root 4689: if(key_recv != 0) {
1.1.1.5 root 4690: key_char = (key_code >> 0) & 0xff;
4691: key_scan = (key_code >> 8) & 0xff;
4692: key_code >>= 16;
1.1.1.33 root 4693: key_recv >>= 16;
1.1.1.5 root 4694: } else {
1.1.1.35 root 4695: while(key_buf_char != NULL && key_buf_scan != NULL && !m_halted) {
4696: if(key_buf_char != NULL && key_buf_scan != NULL) {
4697: #ifdef USE_SERVICE_THREAD
4698: EnterCriticalSection(&key_buf_crit_sect);
4699: #endif
4700: bool empty = key_buf_char->empty();
4701: #ifdef USE_SERVICE_THREAD
4702: LeaveCriticalSection(&key_buf_crit_sect);
4703: #endif
4704: if(!empty) break;
4705: }
1.1.1.23 root 4706: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
4707: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
4708: if(_kbhit()) {
1.1.1.32 root 4709: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4710: #ifdef USE_SERVICE_THREAD
4711: EnterCriticalSection(&key_buf_crit_sect);
4712: #endif
1.1.1.32 root 4713: key_buf_char->write(_getch());
1.1.1.35 root 4714: key_buf_scan->write(0x00);
4715: #ifdef USE_SERVICE_THREAD
4716: LeaveCriticalSection(&key_buf_crit_sect);
4717: #endif
1.1.1.32 root 4718: }
1.1.1.23 root 4719: } else {
4720: Sleep(10);
4721: }
4722: } else {
4723: if(!update_key_buffer()) {
4724: Sleep(10);
4725: }
1.1.1.14 root 4726: }
4727: }
4728: if(m_halted) {
1.1.1.33 root 4729: // insert CR to terminate input loops
1.1.1.14 root 4730: key_char = 0x0d;
4731: key_scan = 0;
1.1.1.32 root 4732: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4733: #ifdef USE_SERVICE_THREAD
4734: EnterCriticalSection(&key_buf_crit_sect);
4735: #endif
1.1.1.14 root 4736: key_char = key_buf_char->read();
4737: key_scan = key_buf_scan->read();
1.1.1.35 root 4738: #ifdef USE_SERVICE_THREAD
4739: LeaveCriticalSection(&key_buf_crit_sect);
4740: #endif
1.1.1.5 root 4741: }
1.1 root 4742: }
4743: if(echo && key_char) {
4744: msdos_putch(key_char);
4745: }
4746: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
4747: }
4748:
4749: inline int msdos_getch()
4750: {
4751: return(msdos_getch_ex(0));
4752: }
4753:
4754: inline int msdos_getche()
4755: {
4756: return(msdos_getch_ex(1));
4757: }
4758:
4759: int msdos_write(int fd, const void *buffer, unsigned int count)
4760: {
4761: static int is_cr = 0;
4762:
4763: if(fd == 1 && !file_handler[1].atty) {
4764: // CR+LF -> LF
4765: UINT8 *buf = (UINT8 *)buffer;
4766: for(unsigned int i = 0; i < count; i++) {
4767: UINT8 data = buf[i];
4768: if(is_cr) {
4769: if(data != 0x0a) {
4770: UINT8 tmp = 0x0d;
4771: _write(1, &tmp, 1);
4772: }
4773: _write(1, &data, 1);
4774: is_cr = 0;
4775: } else if(data == 0x0d) {
4776: is_cr = 1;
4777: } else {
4778: _write(1, &data, 1);
4779: }
4780: }
4781: return(count);
4782: }
1.1.1.14 root 4783: vram_flush();
1.1 root 4784: return(_write(fd, buffer, count));
4785: }
4786:
4787: void msdos_putch(UINT8 data)
1.1.1.35 root 4788: #ifdef USE_SERVICE_THREAD
4789: {
4790: EnterCriticalSection(&putch_crit_sect);
4791: msdos_putch_tmp(data);
4792: LeaveCriticalSection(&putch_crit_sect);
4793: }
4794: void msdos_putch_tmp(UINT8 data)
4795: #endif
1.1 root 4796: {
1.1.1.34 root 4797: CONSOLE_SCREEN_BUFFER_INFO csbi;
4798: SMALL_RECT rect;
4799: COORD co;
1.1 root 4800: static int p = 0;
4801: static int is_kanji = 0;
4802: static int is_esc = 0;
4803: static int stored_x;
4804: static int stored_y;
4805: static WORD stored_a;
1.1.1.20 root 4806: static char tmp[64], out[64];
1.1 root 4807:
4808: msdos_stdio_reopen();
4809:
1.1.1.20 root 4810: process_t *process = msdos_process_info_get(current_psp);
4811: int fd = msdos_psp_get_file_table(1, current_psp);
4812:
4813: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4814: // stdout is redirected to file
1.1.1.20 root 4815: msdos_write(fd, &data, 1);
1.1 root 4816: return;
4817: }
1.1.1.23 root 4818: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4819:
4820: // output to console
4821: tmp[p++] = data;
4822:
1.1.1.14 root 4823: vram_flush();
4824:
1.1 root 4825: if(is_kanji) {
4826: // kanji character
4827: is_kanji = 0;
4828: } else if(is_esc) {
4829: // escape sequense
4830: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
4831: p = is_esc = 0;
4832: } else if(tmp[1] == '=' && p == 4) {
4833: co.X = tmp[3] - 0x20;
1.1.1.14 root 4834: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 4835: SetConsoleCursorPosition(hStdout, co);
4836: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 4837: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 4838: cursor_moved = false;
4839: p = is_esc = 0;
4840: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
4841: GetConsoleScreenBufferInfo(hStdout, &csbi);
4842: co.X = csbi.dwCursorPosition.X;
4843: co.Y = csbi.dwCursorPosition.Y;
4844: WORD wAttributes = csbi.wAttributes;
4845:
4846: if(tmp[1] == 'D') {
4847: co.Y++;
4848: } else if(tmp[1] == 'E') {
4849: co.X = 0;
4850: co.Y++;
4851: } else if(tmp[1] == 'M') {
4852: co.Y--;
4853: } else if(tmp[1] == '*') {
1.1.1.14 root 4854: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4855: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4856: co.X = 0;
4857: co.Y = csbi.srWindow.Top;
1.1 root 4858: } else if(tmp[1] == '[') {
4859: int param[256], params = 0;
4860: memset(param, 0, sizeof(param));
4861: for(int i = 2; i < p; i++) {
4862: if(tmp[i] >= '0' && tmp[i] <= '9') {
4863: param[params] *= 10;
4864: param[params] += tmp[i] - '0';
4865: } else {
4866: params++;
4867: }
4868: }
4869: if(data == 'A') {
1.1.1.14 root 4870: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 4871: } else if(data == 'B') {
1.1.1.14 root 4872: co.Y += (params == 0) ? 1 : param[0];
1.1 root 4873: } else if(data == 'C') {
1.1.1.14 root 4874: co.X += (params == 0) ? 1 : param[0];
1.1 root 4875: } else if(data == 'D') {
1.1.1.14 root 4876: co.X -= (params == 0) ? 1 : param[0];
1.1 root 4877: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 4878: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
4879: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 4880: } else if(data == 'J') {
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);
4885: if(co.Y < csbi.srWindow.Bottom) {
4886: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4887: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4888: }
4889: } else if(param[0] == 1) {
1.1.1.14 root 4890: if(co.Y > csbi.srWindow.Top) {
4891: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
4892: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4893: }
4894: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 4895: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4896: } else if(param[0] == 2) {
1.1.1.14 root 4897: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4898: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4899: co.X = co.Y = 0;
4900: }
4901: } else if(data == 'K') {
1.1.1.14 root 4902: clear_scr_buffer(csbi.wAttributes);
1.1 root 4903: if(param[0] == 0) {
4904: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4905: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4906: } else if(param[0] == 1) {
4907: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 4908: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4909: } else if(param[0] == 2) {
4910: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4911: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4912: }
4913: } else if(data == 'L') {
1.1.1.14 root 4914: if(params == 0) {
4915: param[0] = 1;
1.1 root 4916: }
1.1.1.14 root 4917: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4918: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4919: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4920: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4921: clear_scr_buffer(csbi.wAttributes);
1.1 root 4922: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 4923: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4924: co.X = 0;
4925: } else if(data == 'M') {
1.1.1.14 root 4926: if(params == 0) {
4927: param[0] = 1;
4928: }
4929: if(co.Y + param[0] > csbi.srWindow.Bottom) {
4930: clear_scr_buffer(csbi.wAttributes);
4931: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4932: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4933: } else {
1.1.1.14 root 4934: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4935: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4936: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4937: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4938: clear_scr_buffer(csbi.wAttributes);
1.1 root 4939: }
4940: co.X = 0;
4941: } else if(data == 'h') {
4942: if(tmp[2] == '>' && tmp[3] == '5') {
4943: CONSOLE_CURSOR_INFO cur;
4944: GetConsoleCursorInfo(hStdout, &cur);
4945: if(cur.bVisible) {
4946: cur.bVisible = FALSE;
1.1.1.14 root 4947: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 4948: }
4949: }
4950: } else if(data == 'l') {
4951: if(tmp[2] == '>' && tmp[3] == '5') {
4952: CONSOLE_CURSOR_INFO cur;
4953: GetConsoleCursorInfo(hStdout, &cur);
4954: if(!cur.bVisible) {
4955: cur.bVisible = TRUE;
1.1.1.14 root 4956: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 4957: }
4958: }
4959: } else if(data == 'm') {
4960: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
4961: int reverse = 0, hidden = 0;
4962: for(int i = 0; i < params; i++) {
4963: if(param[i] == 1) {
4964: wAttributes |= FOREGROUND_INTENSITY;
4965: } else if(param[i] == 4) {
4966: wAttributes |= COMMON_LVB_UNDERSCORE;
4967: } else if(param[i] == 7) {
4968: reverse = 1;
4969: } else if(param[i] == 8 || param[i] == 16) {
4970: hidden = 1;
4971: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
4972: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
4973: if(param[i] >= 17 && param[i] <= 23) {
4974: param[i] -= 16;
4975: } else {
4976: param[i] -= 30;
4977: }
4978: if(param[i] & 1) {
4979: wAttributes |= FOREGROUND_RED;
4980: }
4981: if(param[i] & 2) {
4982: wAttributes |= FOREGROUND_GREEN;
4983: }
4984: if(param[i] & 4) {
4985: wAttributes |= FOREGROUND_BLUE;
4986: }
4987: } else if(param[i] >= 40 && param[i] <= 47) {
4988: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
4989: if((param[i] - 40) & 1) {
4990: wAttributes |= BACKGROUND_RED;
4991: }
4992: if((param[i] - 40) & 2) {
4993: wAttributes |= BACKGROUND_GREEN;
4994: }
4995: if((param[i] - 40) & 4) {
4996: wAttributes |= BACKGROUND_BLUE;
4997: }
4998: }
4999: }
5000: if(reverse) {
5001: wAttributes &= ~0xff;
5002: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
5003: }
5004: if(hidden) {
5005: wAttributes &= ~0x0f;
5006: wAttributes |= (wAttributes >> 4) & 0x0f;
5007: }
5008: } else if(data == 'n') {
5009: if(param[0] == 6) {
5010: char tmp[16];
5011: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
5012: int len = strlen(tmp);
1.1.1.32 root 5013: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 5014: #ifdef USE_SERVICE_THREAD
5015: EnterCriticalSection(&key_buf_crit_sect);
5016: #endif
1.1.1.32 root 5017: for(int i = 0; i < len; i++) {
5018: key_buf_char->write(tmp[i]);
5019: key_buf_scan->write(0x00);
5020: }
1.1.1.35 root 5021: #ifdef USE_SERVICE_THREAD
5022: LeaveCriticalSection(&key_buf_crit_sect);
5023: #endif
1.1 root 5024: }
5025: }
5026: } else if(data == 's') {
5027: stored_x = co.X;
5028: stored_y = co.Y;
5029: stored_a = wAttributes;
5030: } else if(data == 'u') {
5031: co.X = stored_x;
5032: co.Y = stored_y;
5033: wAttributes = stored_a;
5034: }
5035: }
5036: if(co.X < 0) {
5037: co.X = 0;
5038: } else if(co.X >= csbi.dwSize.X) {
5039: co.X = csbi.dwSize.X - 1;
5040: }
1.1.1.14 root 5041: if(co.Y < csbi.srWindow.Top) {
5042: co.Y = csbi.srWindow.Top;
5043: } else if(co.Y > csbi.srWindow.Bottom) {
5044: co.Y = csbi.srWindow.Bottom;
1.1 root 5045: }
5046: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
5047: SetConsoleCursorPosition(hStdout, co);
5048: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5049: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 5050: cursor_moved = false;
5051: }
5052: if(wAttributes != csbi.wAttributes) {
5053: SetConsoleTextAttribute(hStdout, wAttributes);
5054: }
5055: p = is_esc = 0;
5056: }
5057: return;
5058: } else {
5059: if(msdos_lead_byte_check(data)) {
5060: is_kanji = 1;
5061: return;
5062: } else if(data == 0x1b) {
5063: is_esc = 1;
5064: return;
5065: }
5066: }
1.1.1.20 root 5067:
5068: DWORD q = 0, num;
5069: is_kanji = 0;
5070: for(int i = 0; i < p; i++) {
5071: UINT8 c = tmp[i];
5072: if(is_kanji) {
5073: is_kanji = 0;
5074: } else if(msdos_lead_byte_check(data)) {
5075: is_kanji = 1;
5076: } else if(msdos_ctrl_code_check(data)) {
5077: out[q++] = '^';
5078: c += 'A' - 1;
5079: }
5080: out[q++] = c;
5081: }
1.1.1.34 root 5082: if(q == 1 && out[0] == 0x08) {
5083: // back space
5084: GetConsoleScreenBufferInfo(hStdout, &csbi);
5085: if(csbi.dwCursorPosition.X > 0) {
5086: co.X = csbi.dwCursorPosition.X - 1;
5087: co.Y = csbi.dwCursorPosition.Y;
5088: SetConsoleCursorPosition(hStdout, co);
5089: } else if(csbi.dwCursorPosition.Y > 0) {
5090: co.X = csbi.dwSize.X - 1;
5091: co.Y = csbi.dwCursorPosition.Y - 1;
5092: SetConsoleCursorPosition(hStdout, co);
5093: } else {
5094: WriteConsole(hStdout, out, q, &num, NULL); // to make sure
5095: }
5096: } else {
5097: WriteConsole(hStdout, out, q, &num, NULL);
5098: }
1.1 root 5099: p = 0;
1.1.1.14 root 5100:
1.1.1.15 root 5101: if(!restore_console_on_exit) {
5102: GetConsoleScreenBufferInfo(hStdout, &csbi);
5103: scr_top = csbi.srWindow.Top;
5104: }
1.1 root 5105: cursor_moved = true;
5106: }
5107:
5108: int msdos_aux_in()
5109: {
1.1.1.21 root 5110: msdos_stdio_reopen();
5111:
1.1.1.20 root 5112: process_t *process = msdos_process_info_get(current_psp);
5113: int fd = msdos_psp_get_file_table(3, current_psp);
5114:
5115: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 5116: char data = 0;
1.1.1.20 root 5117: _read(fd, &data, 1);
1.1 root 5118: return(data);
5119: } else {
5120: return(EOF);
5121: }
5122: }
5123:
5124: void msdos_aux_out(char data)
5125: {
1.1.1.21 root 5126: msdos_stdio_reopen();
5127:
1.1.1.20 root 5128: process_t *process = msdos_process_info_get(current_psp);
5129: int fd = msdos_psp_get_file_table(3, current_psp);
5130:
5131: if(fd < process->max_files && file_handler[fd].valid) {
5132: msdos_write(fd, &data, 1);
1.1 root 5133: }
5134: }
5135:
5136: void msdos_prn_out(char data)
5137: {
1.1.1.21 root 5138: msdos_stdio_reopen();
5139:
1.1.1.20 root 5140: process_t *process = msdos_process_info_get(current_psp);
5141: int fd = msdos_psp_get_file_table(4, current_psp);
5142:
5143: if(fd < process->max_files && file_handler[fd].valid) {
5144: msdos_write(fd, &data, 1);
1.1 root 5145: }
5146: }
5147:
5148: // memory control
5149:
1.1.1.19 root 5150: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 5151: {
5152: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5153:
5154: mcb->mz = mz;
5155: mcb->psp = psp;
1.1.1.30 root 5156: mcb->paragraphs = paragraphs;
1.1 root 5157: return(mcb);
5158: }
5159:
5160: void msdos_mcb_check(mcb_t *mcb)
5161: {
5162: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 5163: #if 0
5164: // shutdown now !!!
5165: fatalerror("broken memory control block\n");
5166: #else
5167: // return error code and continue
5168: throw(0x07); // broken memory control block
5169: #endif
1.1 root 5170: }
5171: }
5172:
5173: int msdos_mem_split(int seg, int paragraphs)
5174: {
5175: int mcb_seg = seg - 1;
5176: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5177: msdos_mcb_check(mcb);
5178:
1.1.1.30 root 5179: if(mcb->paragraphs > paragraphs) {
1.1 root 5180: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 5181: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 5182:
5183: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5184: mcb->mz = 'M';
1.1.1.30 root 5185: mcb->paragraphs = paragraphs;
1.1 root 5186: return(0);
5187: }
5188: return(-1);
5189: }
5190:
5191: void msdos_mem_merge(int seg)
5192: {
5193: int mcb_seg = seg - 1;
5194: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5195: msdos_mcb_check(mcb);
5196:
5197: while(1) {
5198: if(mcb->mz == 'Z') {
5199: break;
5200: }
1.1.1.30 root 5201: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 5202: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5203: msdos_mcb_check(next_mcb);
5204:
5205: if(next_mcb->psp != 0) {
5206: break;
5207: }
5208: mcb->mz = next_mcb->mz;
1.1.1.30 root 5209: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 5210: }
5211: }
5212:
1.1.1.8 root 5213: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 5214: {
5215: while(1) {
5216: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5217: bool last_block;
1.1 root 5218:
1.1.1.14 root 5219: if(mcb->psp == 0) {
5220: msdos_mem_merge(mcb_seg + 1);
5221: } else {
5222: msdos_mcb_check(mcb);
5223: }
1.1.1.33 root 5224: if(!(last_block = (mcb->mz == 'Z'))) {
5225: // check if the next is dummy mcb to link to umb
5226: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5227: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5228: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5229: }
5230: if(!(new_process && !last_block)) {
1.1.1.30 root 5231: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 5232: msdos_mem_split(mcb_seg + 1, paragraphs);
5233: mcb->psp = current_psp;
5234: return(mcb_seg + 1);
5235: }
5236: }
5237: if(mcb->mz == 'Z') {
5238: break;
5239: }
1.1.1.30 root 5240: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5241: }
5242: return(-1);
5243: }
5244:
5245: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5246: {
5247: int mcb_seg = seg - 1;
5248: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5249: msdos_mcb_check(mcb);
1.1.1.30 root 5250: int current_paragraphs = mcb->paragraphs;
1.1 root 5251:
5252: msdos_mem_merge(seg);
1.1.1.30 root 5253: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 5254: if(max_paragraphs) {
1.1.1.30 root 5255: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 5256: }
1.1 root 5257: msdos_mem_split(seg, current_paragraphs);
5258: return(-1);
5259: }
5260: msdos_mem_split(seg, paragraphs);
5261: return(0);
5262: }
5263:
5264: void msdos_mem_free(int seg)
5265: {
5266: int mcb_seg = seg - 1;
5267: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5268: msdos_mcb_check(mcb);
5269:
5270: mcb->psp = 0;
5271: msdos_mem_merge(seg);
5272: }
5273:
1.1.1.8 root 5274: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 5275: {
5276: int max_paragraphs = 0;
5277:
5278: while(1) {
5279: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5280: bool last_block;
5281:
1.1 root 5282: msdos_mcb_check(mcb);
5283:
1.1.1.33 root 5284: if(!(last_block = (mcb->mz == 'Z'))) {
5285: // check if the next is dummy mcb to link to umb
5286: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5287: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5288: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5289: }
5290: if(!(new_process && !last_block)) {
1.1.1.30 root 5291: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
5292: max_paragraphs = mcb->paragraphs;
1.1 root 5293: }
5294: }
5295: if(mcb->mz == 'Z') {
5296: break;
5297: }
1.1.1.30 root 5298: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5299: }
1.1.1.14 root 5300: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 5301: }
5302:
1.1.1.8 root 5303: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
5304: {
5305: int last_seg = -1;
5306:
5307: while(1) {
5308: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5309: msdos_mcb_check(mcb);
5310:
1.1.1.14 root 5311: if(mcb->psp == psp) {
1.1.1.8 root 5312: last_seg = mcb_seg;
5313: }
1.1.1.14 root 5314: if(mcb->mz == 'Z') {
5315: break;
5316: }
1.1.1.30 root 5317: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 5318: }
5319: return(last_seg);
5320: }
5321:
1.1.1.19 root 5322: int msdos_mem_get_umb_linked()
5323: {
1.1.1.33 root 5324: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5325: msdos_mcb_check(mcb);
1.1.1.19 root 5326:
1.1.1.33 root 5327: if(mcb->mz == 'M') {
5328: return(-1);
1.1.1.19 root 5329: }
5330: return(0);
5331: }
5332:
1.1.1.33 root 5333: void msdos_mem_link_umb()
1.1.1.19 root 5334: {
1.1.1.33 root 5335: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5336: msdos_mcb_check(mcb);
1.1.1.19 root 5337:
1.1.1.33 root 5338: mcb->mz = 'M';
5339: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
1.1.1.19 root 5340: }
5341:
1.1.1.33 root 5342: void msdos_mem_unlink_umb()
1.1.1.19 root 5343: {
1.1.1.33 root 5344: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5345: msdos_mcb_check(mcb);
1.1.1.19 root 5346:
1.1.1.33 root 5347: mcb->mz = 'Z';
5348: mcb->paragraphs = 0;
1.1.1.19 root 5349: }
5350:
1.1.1.29 root 5351: #ifdef SUPPORT_HMA
5352:
5353: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
5354: {
5355: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5356:
5357: mcb->ms[0] = 'M';
5358: mcb->ms[1] = 'S';
5359: mcb->owner = owner;
5360: mcb->size = size;
5361: mcb->next = next;
5362: return(mcb);
5363: }
5364:
5365: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
5366: {
5367: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
5368: }
5369:
5370: int msdos_hma_mem_split(int offset, int size)
5371: {
5372: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5373:
5374: if(!msdos_is_hma_mcb_valid(mcb)) {
5375: return(-1);
5376: }
5377: if(mcb->size >= size + 0x10) {
5378: int new_offset = offset + 0x10 + size;
5379: int new_size = mcb->size - 0x10 - size;
5380:
5381: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
5382: mcb->size = size;
5383: mcb->next = new_offset;
5384: return(0);
5385: }
5386: return(-1);
5387: }
5388:
5389: void msdos_hma_mem_merge(int offset)
5390: {
5391: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5392:
5393: if(!msdos_is_hma_mcb_valid(mcb)) {
5394: return;
5395: }
5396: while(1) {
5397: if(mcb->next == 0) {
5398: break;
5399: }
5400: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
5401:
5402: if(!msdos_is_hma_mcb_valid(next_mcb)) {
5403: return;
5404: }
5405: if(next_mcb->owner != 0) {
5406: break;
5407: }
5408: mcb->size += 0x10 + next_mcb->size;
5409: mcb->next = next_mcb->next;
5410: }
5411: }
5412:
5413: int msdos_hma_mem_alloc(int size, UINT16 owner)
5414: {
5415: int offset = 0x10; // first mcb in HMA
5416:
5417: while(1) {
5418: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5419:
5420: if(!msdos_is_hma_mcb_valid(mcb)) {
5421: return(-1);
5422: }
5423: if(mcb->owner == 0) {
5424: msdos_hma_mem_merge(offset);
5425: }
5426: if(mcb->owner == 0 && mcb->size >= size) {
5427: msdos_hma_mem_split(offset, size);
5428: mcb->owner = owner;
5429: return(offset);
5430: }
5431: if(mcb->next == 0) {
5432: break;
5433: }
5434: offset = mcb->next;
5435: }
5436: return(-1);
5437: }
5438:
5439: int msdos_hma_mem_realloc(int offset, int size)
5440: {
5441: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5442:
5443: if(!msdos_is_hma_mcb_valid(mcb)) {
5444: return(-1);
5445: }
5446: if(mcb->size < size) {
5447: return(-1);
5448: }
5449: msdos_hma_mem_split(offset, size);
5450: return(0);
5451: }
5452:
5453: void msdos_hma_mem_free(int offset)
5454: {
5455: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5456:
5457: if(!msdos_is_hma_mcb_valid(mcb)) {
5458: return;
5459: }
5460: mcb->owner = 0;
5461: msdos_hma_mem_merge(offset);
5462: }
5463:
5464: int msdos_hma_mem_get_free(int *available_offset)
5465: {
5466: int offset = 0x10; // first mcb in HMA
5467: int size = 0;
5468:
5469: while(1) {
5470: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5471:
5472: if(!msdos_is_hma_mcb_valid(mcb)) {
5473: return(0);
5474: }
5475: if(mcb->owner == 0 && size < mcb->size) {
5476: if(available_offset != NULL) {
5477: *available_offset = offset;
5478: }
5479: size = mcb->size;
5480: }
5481: if(mcb->next == 0) {
5482: break;
5483: }
5484: offset = mcb->next;
5485: }
5486: return(size);
5487: }
5488:
5489: #endif
5490:
1.1 root 5491: // environment
5492:
5493: void msdos_env_set_argv(int env_seg, char *argv)
5494: {
5495: char *dst = (char *)(mem + (env_seg << 4));
5496:
5497: while(1) {
5498: if(dst[0] == 0) {
5499: break;
5500: }
5501: dst += strlen(dst) + 1;
5502: }
5503: *dst++ = 0; // end of environment
5504: *dst++ = 1; // top of argv[0]
5505: *dst++ = 0;
5506: memcpy(dst, argv, strlen(argv));
5507: dst += strlen(argv);
5508: *dst++ = 0;
5509: *dst++ = 0;
5510: }
5511:
5512: char *msdos_env_get_argv(int env_seg)
5513: {
5514: static char env[ENV_SIZE];
5515: char *src = env;
5516:
5517: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5518: while(1) {
5519: if(src[0] == 0) {
5520: if(src[1] == 1) {
5521: return(src + 3);
5522: }
5523: break;
5524: }
5525: src += strlen(src) + 1;
5526: }
5527: return(NULL);
5528: }
5529:
5530: char *msdos_env_get(int env_seg, const char *name)
5531: {
5532: static char env[ENV_SIZE];
5533: char *src = env;
5534:
5535: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5536: while(1) {
5537: if(src[0] == 0) {
5538: break;
5539: }
5540: int len = strlen(src);
5541: char *n = my_strtok(src, "=");
5542: char *v = src + strlen(n) + 1;
5543:
5544: if(_stricmp(name, n) == 0) {
5545: return(v);
5546: }
5547: src += len + 1;
5548: }
5549: return(NULL);
5550: }
5551:
5552: void msdos_env_set(int env_seg, char *name, char *value)
5553: {
5554: char env[ENV_SIZE];
5555: char *src = env;
5556: char *dst = (char *)(mem + (env_seg << 4));
5557: char *argv = msdos_env_get_argv(env_seg);
5558: int done = 0;
5559:
5560: memcpy(src, dst, ENV_SIZE);
5561: memset(dst, 0, ENV_SIZE);
5562: while(1) {
5563: if(src[0] == 0) {
5564: break;
5565: }
5566: int len = strlen(src);
5567: char *n = my_strtok(src, "=");
5568: char *v = src + strlen(n) + 1;
5569: char tmp[1024];
5570:
5571: if(_stricmp(name, n) == 0) {
5572: sprintf(tmp, "%s=%s", n, value);
5573: done = 1;
5574: } else {
5575: sprintf(tmp, "%s=%s", n, v);
5576: }
5577: memcpy(dst, tmp, strlen(tmp));
5578: dst += strlen(tmp) + 1;
5579: src += len + 1;
5580: }
5581: if(!done) {
5582: char tmp[1024];
5583:
5584: sprintf(tmp, "%s=%s", name, value);
5585: memcpy(dst, tmp, strlen(tmp));
5586: dst += strlen(tmp) + 1;
5587: }
5588: if(argv) {
5589: *dst++ = 0; // end of environment
5590: *dst++ = 1; // top of argv[0]
5591: *dst++ = 0;
5592: memcpy(dst, argv, strlen(argv));
5593: dst += strlen(argv);
5594: *dst++ = 0;
5595: *dst++ = 0;
5596: }
5597: }
5598:
5599: // process
5600:
1.1.1.8 root 5601: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 5602: {
5603: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5604:
5605: memset(psp, 0, PSP_SIZE);
5606: psp->exit[0] = 0xcd;
5607: psp->exit[1] = 0x20;
1.1.1.8 root 5608: psp->first_mcb = mcb_seg;
1.1 root 5609: psp->far_call = 0xea;
5610: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
5611: psp->cpm_entry.w.h = 0xf000;
5612: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5613: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5614: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5615: psp->parent_psp = parent_psp;
1.1.1.20 root 5616: if(parent_psp == (UINT16)-1) {
5617: for(int i = 0; i < 20; i++) {
5618: if(file_handler[i].valid) {
5619: psp->file_table[i] = i;
5620: } else {
5621: psp->file_table[i] = 0xff;
5622: }
1.1 root 5623: }
1.1.1.20 root 5624: } else {
5625: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 5626: }
5627: psp->env_seg = env_seg;
5628: psp->stack.w.l = REG16(SP);
1.1.1.3 root 5629: psp->stack.w.h = SREG(SS);
1.1.1.14 root 5630: psp->file_table_size = 20;
5631: psp->file_table_ptr.w.l = 0x18;
5632: psp->file_table_ptr.w.h = psp_seg;
1.1 root 5633: psp->service[0] = 0xcd;
5634: psp->service[1] = 0x21;
5635: psp->service[2] = 0xcb;
5636: return(psp);
5637: }
5638:
1.1.1.20 root 5639: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
5640: {
5641: if(psp_seg && fd < 20) {
5642: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5643: psp->file_table[fd] = value;
5644: }
5645: }
5646:
5647: int msdos_psp_get_file_table(int fd, int psp_seg)
5648: {
5649: if(psp_seg && fd < 20) {
5650: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5651: fd = psp->file_table[fd];
5652: }
5653: return fd;
5654: }
5655:
1.1 root 5656: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
5657: {
5658: // load command file
5659: int fd = -1;
5660: int dos_command = 0;
1.1.1.24 root 5661: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 5662:
5663: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5664: int opt_len = mem[opt_ofs];
5665: memset(opt, 0, sizeof(opt));
5666: memcpy(opt, mem + opt_ofs + 1, opt_len);
5667:
1.1.1.14 root 5668: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
5669: // this is a batch file, run command.com
5670: char tmp[MAX_PATH];
5671: if(opt_len != 0) {
5672: sprintf(tmp, "/C %s %s", cmd, opt);
5673: } else {
5674: sprintf(tmp, "/C %s", cmd);
5675: }
5676: strcpy(opt, tmp);
5677: opt_len = strlen(opt);
5678: mem[opt_ofs] = opt_len;
5679: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5680: strcpy(command, comspec_path);
5681: strcpy(name_tmp, "COMMAND.COM");
5682: } else {
5683: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
5684: // redirect C:\COMMAND.COM to comspec_path
5685: strcpy(command, comspec_path);
5686: } else {
5687: strcpy(command, cmd);
5688: }
1.1.1.24 root 5689: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
5690: return(-1);
5691: }
1.1.1.14 root 5692: memset(name_tmp, 0, sizeof(name_tmp));
5693: strcpy(name_tmp, name);
5694:
5695: // check command.com
5696: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
5697: if(opt_len == 0) {
5698: // process_t *current_process = msdos_process_info_get(current_psp);
5699: process_t *current_process = NULL;
5700: for(int i = 0; i < MAX_PROCESS; i++) {
5701: if(process[i].psp == current_psp) {
5702: current_process = &process[i];
5703: break;
5704: }
5705: }
5706: if(current_process != NULL) {
5707: param->cmd_line.dw = current_process->dta.dw;
5708: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5709: opt_len = mem[opt_ofs];
5710: memset(opt, 0, sizeof(opt));
5711: memcpy(opt, mem + opt_ofs + 1, opt_len);
5712: }
5713: }
5714: for(int i = 0; i < opt_len; i++) {
5715: if(opt[i] == ' ') {
5716: continue;
5717: }
5718: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
5719: for(int j = i + 3; j < opt_len; j++) {
5720: if(opt[j] == ' ') {
5721: continue;
5722: }
5723: char *token = my_strtok(opt + j, " ");
5724:
5725: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
5726: // this is a batch file, okay to run command.com
5727: } else {
5728: // run program directly without command.com
5729: strcpy(command, token);
5730: char tmp[MAX_PATH];
5731: strcpy(tmp, token + strlen(token) + 1);
5732: strcpy(opt, tmp);
5733: opt_len = strlen(opt);
5734: mem[opt_ofs] = opt_len;
5735: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5736: dos_command = 1;
5737: }
5738: break;
1.1 root 5739: }
5740: }
1.1.1.14 root 5741: break;
1.1 root 5742: }
5743: }
5744: }
5745:
5746: // load command file
5747: strcpy(path, command);
5748: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5749: sprintf(path, "%s.COM", command);
5750: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5751: sprintf(path, "%s.EXE", command);
5752: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 5753: sprintf(path, "%s.BAT", command);
5754: if(_access(path, 0) == 0) {
5755: // this is a batch file, run command.com
5756: char tmp[MAX_PATH];
5757: if(opt_len != 0) {
5758: sprintf(tmp, "/C %s %s", path, opt);
5759: } else {
5760: sprintf(tmp, "/C %s", path);
5761: }
5762: strcpy(opt, tmp);
5763: opt_len = strlen(opt);
5764: mem[opt_ofs] = opt_len;
5765: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5766: strcpy(path, comspec_path);
5767: strcpy(name_tmp, "COMMAND.COM");
5768: fd = _open(path, _O_RDONLY | _O_BINARY);
5769: } else {
5770: // search path in parent environments
5771: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5772: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
5773: if(env != NULL) {
5774: char env_path[4096];
5775: strcpy(env_path, env);
5776: char *token = my_strtok(env_path, ";");
5777:
5778: while(token != NULL) {
5779: if(strlen(token) != 0) {
5780: sprintf(path, "%s", msdos_combine_path(token, command));
5781: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5782: break;
5783: }
5784: sprintf(path, "%s.COM", msdos_combine_path(token, command));
5785: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5786: break;
5787: }
5788: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
5789: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5790: break;
5791: }
5792: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
5793: if(_access(path, 0) == 0) {
5794: // this is a batch file, run command.com
5795: char tmp[MAX_PATH];
5796: if(opt_len != 0) {
5797: sprintf(tmp, "/C %s %s", path, opt);
5798: } else {
5799: sprintf(tmp, "/C %s", path);
5800: }
5801: strcpy(opt, tmp);
5802: opt_len = strlen(opt);
5803: mem[opt_ofs] = opt_len;
5804: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5805: strcpy(path, comspec_path);
5806: strcpy(name_tmp, "COMMAND.COM");
5807: fd = _open(path, _O_RDONLY | _O_BINARY);
5808: break;
5809: }
1.1.1.8 root 5810: }
1.1.1.14 root 5811: token = my_strtok(NULL, ";");
1.1 root 5812: }
5813: }
5814: }
5815: }
5816: }
5817: }
5818: if(fd == -1) {
5819: if(dos_command) {
5820: // may be dos command
5821: char tmp[MAX_PATH];
5822: sprintf(tmp, "%s %s", command, opt);
5823: system(tmp);
5824: return(0);
5825: } else {
5826: return(-1);
5827: }
5828: }
5829: _read(fd, file_buffer, sizeof(file_buffer));
5830: _close(fd);
5831:
5832: // copy environment
1.1.1.29 root 5833: int umb_linked, env_seg, psp_seg;
1.1 root 5834:
1.1.1.29 root 5835: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
5836: msdos_mem_unlink_umb();
5837: }
1.1.1.8 root 5838: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 5839: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
5840: if(umb_linked != 0) {
5841: msdos_mem_link_umb();
5842: }
5843: return(-1);
5844: }
1.1 root 5845: }
5846: if(param->env_seg == 0) {
5847: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5848: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
5849: } else {
5850: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
5851: }
5852: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
5853:
5854: // check exe header
5855: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 5856: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 5857: UINT16 cs, ss, ip, sp;
5858:
5859: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
5860: // memory allocation
5861: int header_size = header->header_size * 16;
5862: int load_size = header->pages * 512 - header_size;
5863: if(header_size + load_size < 512) {
5864: load_size = 512 - header_size;
5865: }
5866: paragraphs = (PSP_SIZE + load_size) >> 4;
5867: if(paragraphs + header->min_alloc > free_paragraphs) {
5868: msdos_mem_free(env_seg);
5869: return(-1);
5870: }
5871: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
5872: if(paragraphs > free_paragraphs) {
5873: paragraphs = free_paragraphs;
5874: }
1.1.1.8 root 5875: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 5876: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
5877: if(umb_linked != 0) {
5878: msdos_mem_link_umb();
5879: }
5880: msdos_mem_free(env_seg);
5881: return(-1);
5882: }
1.1 root 5883: }
5884: // relocation
5885: int start_seg = psp_seg + (PSP_SIZE >> 4);
5886: for(int i = 0; i < header->relocations; i++) {
5887: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
5888: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
5889: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
5890: }
5891: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
5892: // segments
5893: cs = header->init_cs + start_seg;
5894: ss = header->init_ss + start_seg;
5895: ip = header->init_ip;
5896: sp = header->init_sp - 2; // for symdeb
5897: } else {
5898: // memory allocation
5899: paragraphs = free_paragraphs;
1.1.1.8 root 5900: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 5901: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
5902: if(umb_linked != 0) {
5903: msdos_mem_link_umb();
5904: }
5905: msdos_mem_free(env_seg);
5906: return(-1);
5907: }
1.1 root 5908: }
5909: int start_seg = psp_seg + (PSP_SIZE >> 4);
5910: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
5911: // segments
5912: cs = ss = psp_seg;
5913: ip = 0x100;
5914: sp = 0xfffe;
5915: }
1.1.1.29 root 5916: if(umb_linked != 0) {
5917: msdos_mem_link_umb();
5918: }
1.1 root 5919:
5920: // create psp
1.1.1.3 root 5921: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
5922: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 5923: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
5924: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
5925: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
5926: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
5927:
5928: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
5929: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
5930: mcb_psp->psp = mcb_env->psp = psp_seg;
5931:
1.1.1.4 root 5932: for(int i = 0; i < 8; i++) {
5933: if(name_tmp[i] == '.') {
5934: mcb_psp->prog_name[i] = '\0';
5935: break;
5936: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
5937: mcb_psp->prog_name[i] = name_tmp[i];
5938: i++;
5939: mcb_psp->prog_name[i] = name_tmp[i];
5940: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
5941: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
5942: } else {
5943: mcb_psp->prog_name[i] = name_tmp[i];
5944: }
5945: }
5946:
1.1 root 5947: // process info
5948: process_t *process = msdos_process_info_create(psp_seg);
5949: strcpy(process->module_dir, msdos_short_full_dir(path));
1.1.1.33 root 5950: #ifdef USE_DEBUGGER
5951: strcpy(process->module_path, path);
5952: #endif
1.1 root 5953: process->dta.w.l = 0x80;
5954: process->dta.w.h = psp_seg;
5955: process->switchar = '/';
5956: process->max_files = 20;
5957: process->parent_int_10h_feh_called = int_10h_feh_called;
5958: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 5959: process->parent_ds = SREG(DS);
1.1.1.31 root 5960: process->parent_es = SREG(ES);
1.1 root 5961:
5962: current_psp = psp_seg;
1.1.1.23 root 5963: msdos_sda_update(current_psp);
1.1 root 5964:
5965: if(al == 0x00) {
5966: int_10h_feh_called = int_10h_ffh_called = false;
5967:
5968: // registers and segments
5969: REG16(AX) = REG16(BX) = 0x00;
5970: REG16(CX) = 0xff;
5971: REG16(DX) = psp_seg;
5972: REG16(SI) = ip;
5973: REG16(DI) = sp;
5974: REG16(SP) = sp;
1.1.1.3 root 5975: SREG(DS) = SREG(ES) = psp_seg;
5976: SREG(SS) = ss;
5977: i386_load_segment_descriptor(DS);
5978: i386_load_segment_descriptor(ES);
5979: i386_load_segment_descriptor(SS);
1.1 root 5980:
5981: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
5982: i386_jmp_far(cs, ip);
5983: } else if(al == 0x01) {
5984: // copy ss:sp and cs:ip to param block
5985: param->sp = sp;
5986: param->ss = ss;
5987: param->ip = ip;
5988: param->cs = cs;
1.1.1.31 root 5989:
5990: // the AX value to be passed to the child program is put on top of the child's stack
5991: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 5992: }
5993: return(0);
5994: }
5995:
5996: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
5997: {
5998: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5999:
6000: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
6001: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
6002: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
6003:
1.1.1.3 root 6004: SREG(SS) = psp->stack.w.h;
6005: i386_load_segment_descriptor(SS);
1.1 root 6006: REG16(SP) = psp->stack.w.l;
6007: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
6008:
1.1.1.28 root 6009: // process_t *current_process = msdos_process_info_get(psp_seg);
6010: process_t *current_process = NULL;
6011: for(int i = 0; i < MAX_PROCESS; i++) {
6012: if(process[i].psp == psp_seg) {
6013: current_process = &process[i];
6014: break;
6015: }
6016: }
6017: if(current_process == NULL) {
6018: throw(0x1f); // general failure
6019: }
6020: int_10h_feh_called = current_process->parent_int_10h_feh_called;
6021: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
6022: if(current_process->called_by_int2eh) {
6023: REG16(AX) = ret;
6024: }
6025: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 6026: SREG(ES) = current_process->parent_es;
1.1.1.14 root 6027: i386_load_segment_descriptor(DS);
1.1.1.31 root 6028: i386_load_segment_descriptor(ES);
1.1 root 6029:
6030: if(mem_free) {
1.1.1.8 root 6031: int mcb_seg;
6032: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
6033: msdos_mem_free(mcb_seg + 1);
6034: }
6035: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
6036: msdos_mem_free(mcb_seg + 1);
6037: }
1.1 root 6038:
6039: for(int i = 0; i < MAX_FILES; i++) {
6040: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
6041: _close(i);
1.1.1.20 root 6042: msdos_file_handler_close(i);
6043: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 6044: }
6045: }
1.1.1.13 root 6046: msdos_dta_info_free(psp_seg);
1.1 root 6047: }
1.1.1.14 root 6048: msdos_stdio_reopen();
1.1 root 6049:
1.1.1.28 root 6050: memset(current_process, 0, sizeof(process_t));
1.1 root 6051:
6052: current_psp = psp->parent_psp;
6053: retval = ret;
1.1.1.23 root 6054: msdos_sda_update(current_psp);
1.1 root 6055: }
6056:
6057: // drive
6058:
6059: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
6060: {
6061: *seg = DPB_TOP >> 4;
6062: *ofs = sizeof(dpb_t) * drive_num;
6063: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
6064:
6065: if(!force_update && dpb->free_clusters != 0) {
6066: return(dpb->bytes_per_sector ? 1 : 0);
6067: }
6068: memset(dpb, 0, sizeof(dpb_t));
6069:
6070: int res = 0;
6071: char dev[64];
6072: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
6073:
1.1.1.17 root 6074: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 6075: if(hFile != INVALID_HANDLE_VALUE) {
6076: DISK_GEOMETRY geo;
6077: DWORD dwSize;
6078: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6079: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
6080: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
6081: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 6082: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 6083: switch(geo.MediaType) {
6084: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6085: dpb->media_type = 0xff;
6086: break;
6087: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6088: dpb->media_type = 0xfe;
6089: break;
6090: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6091: dpb->media_type = 0xfd;
6092: break;
6093: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6094: dpb->media_type = 0xfc;
6095: break;
6096: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6097: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6098: dpb->media_type = 0xf9;
6099: break;
6100: case FixedMedia: // hard disk
6101: case RemovableMedia:
1.1.1.19 root 6102: case Unknown:
1.1 root 6103: dpb->media_type = 0xf8;
6104: break;
6105: default:
6106: dpb->media_type = 0xf0;
6107: break;
6108: }
6109: res = 1;
6110: }
6111: dpb->drive_num = drive_num;
6112: dpb->unit_num = drive_num;
6113: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
6114: dpb->next_dpb_seg = *seg;
1.1.1.14 root 6115: dpb->info_sector = 0xffff;
6116: dpb->backup_boot_sector = 0xffff;
1.1 root 6117: dpb->free_clusters = 0xffff;
1.1.1.14 root 6118: dpb->free_search_cluster = 0xffffffff;
1.1 root 6119: CloseHandle(hFile);
6120: }
6121: return(res);
6122: }
6123:
6124: // pc bios
6125:
1.1.1.35 root 6126: #ifdef USE_SERVICE_THREAD
6127: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress)
6128: {
6129: #if defined(HAS_I386)
6130: if(m_SF != 0) {
6131: m_SF = 0;
6132: mem[0xfffd0 + 0x15] = 0x79; // jns -4
6133: } else {
6134: m_SF = 1;
6135: mem[0xfffd0 + 0x15] = 0x78; // js -4
6136: }
6137: #else
6138: if(m_SignVal < 0) {
6139: m_SignVal = 0;
6140: mem[0xfffd0 + 0x15] = 0x79; // jns -4
6141: } else {
6142: m_SignVal = -1;
6143: mem[0xfffd0 + 0x15] = 0x78; // js -4
6144: }
6145: #endif
6146: i386_call_far(0xfffd, 0x0013);
6147: in_service = true;
6148: service_exit = false;
6149: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL));
6150: }
6151:
6152: void finish_service_loop()
6153: {
6154: if(in_service && service_exit) {
6155: #if defined(HAS_I386)
6156: if(m_SF != 0) {
6157: m_SF = 0;
6158: } else {
6159: m_SF = 1;
6160: }
6161: #else
6162: if(m_SignVal < 0) {
6163: m_SignVal = 0;
6164: } else {
6165: m_SignVal = -1;
6166: }
6167: #endif
6168: in_service = false;
6169: }
6170: }
6171: #endif
6172:
1.1.1.19 root 6173: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
6174: {
6175: static unsigned __int64 start_msec_since_midnight = 0;
6176: static unsigned __int64 start_msec_since_hostboot = 0;
6177:
6178: if(start_msec_since_midnight == 0) {
6179: SYSTEMTIME time;
6180: GetLocalTime(&time);
6181: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
6182: start_msec_since_hostboot = cur_msec;
6183: }
6184: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
6185: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
6186: return (UINT32)tick;
6187: }
6188:
6189: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
6190: {
6191: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
6192: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
6193:
6194: if(prev_tick > next_tick) {
6195: mem[0x470] = 1;
6196: }
6197: *(UINT32 *)(mem + 0x46c) = next_tick;
6198: }
6199:
1.1.1.14 root 6200: inline void pcbios_irq0()
6201: {
6202: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 6203: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 6204: }
6205:
1.1.1.16 root 6206: int pcbios_get_text_vram_address(int page)
1.1 root 6207: {
6208: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6209: return TEXT_VRAM_TOP;
1.1 root 6210: } else {
1.1.1.14 root 6211: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 6212: }
6213: }
6214:
1.1.1.16 root 6215: int pcbios_get_shadow_buffer_address(int page)
1.1 root 6216: {
1.1.1.14 root 6217: if(!int_10h_feh_called) {
1.1.1.16 root 6218: return pcbios_get_text_vram_address(page);
1.1.1.14 root 6219: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6220: return SHADOW_BUF_TOP;
6221: } else {
1.1.1.14 root 6222: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 6223: }
6224: }
6225:
1.1.1.16 root 6226: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 6227: {
1.1.1.16 root 6228: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 6229: }
6230:
1.1.1.16 root 6231: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 6232: {
1.1.1.14 root 6233: // clear the existing screen, not just the new one
6234: int clr_height = max(height, scr_height);
6235:
1.1.1.16 root 6236: if(scr_width != width || scr_height != height) {
6237: change_console_size(width, height);
1.1.1.14 root 6238: }
6239: mem[0x462] = 0;
6240: *(UINT16 *)(mem + 0x44e) = 0;
6241:
1.1.1.16 root 6242: text_vram_top_address = pcbios_get_text_vram_address(0);
6243: text_vram_end_address = text_vram_top_address + width * height * 2;
6244: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
6245: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 6246:
1.1.1.23 root 6247: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 6248: if(clr_screen) {
1.1.1.14 root 6249: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
6250: mem[ofs++] = 0x20;
6251: mem[ofs++] = 0x07;
6252: }
6253:
1.1.1.35 root 6254: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6255: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6256: #endif
1.1.1.14 root 6257: for(int y = 0; y < clr_height; y++) {
6258: for(int x = 0; x < scr_width; x++) {
6259: SCR_BUF(y,x).Char.AsciiChar = ' ';
6260: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 6261: }
6262: }
6263: SMALL_RECT rect;
1.1.1.14 root 6264: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
6265: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6266: vram_length_char = vram_last_length_char = 0;
6267: vram_length_attr = vram_last_length_attr = 0;
1.1.1.35 root 6268: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6269: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6270: #endif
1.1 root 6271: }
1.1.1.14 root 6272: COORD co;
6273: co.X = 0;
6274: co.Y = scr_top;
6275: SetConsoleCursorPosition(hStdout, co);
6276: cursor_moved = true;
6277: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 6278: }
6279:
1.1.1.36! root 6280: void pcbios_update_cursor_position()
! 6281: {
! 6282: CONSOLE_SCREEN_BUFFER_INFO csbi;
! 6283: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
! 6284: if(!restore_console_on_exit) {
! 6285: scr_top = csbi.srWindow.Top;
! 6286: }
! 6287: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
! 6288: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
! 6289: }
! 6290:
1.1.1.16 root 6291: inline void pcbios_int_10h_00h()
6292: {
6293: switch(REG8(AL) & 0x7f) {
6294: case 0x70: // v-text mode
6295: case 0x71: // extended cga v-text mode
6296: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
6297: break;
6298: default:
6299: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
6300: break;
6301: }
6302: if(REG8(AL) & 0x80) {
6303: mem[0x487] |= 0x80;
6304: } else {
6305: mem[0x487] &= ~0x80;
6306: }
6307: mem[0x449] = REG8(AL) & 0x7f;
6308: }
6309:
1.1 root 6310: inline void pcbios_int_10h_01h()
6311: {
1.1.1.13 root 6312: mem[0x460] = REG8(CL);
6313: mem[0x461] = REG8(CH);
1.1.1.14 root 6314:
1.1.1.23 root 6315: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6316: CONSOLE_CURSOR_INFO ci;
6317: GetConsoleCursorInfo(hStdout, &ci);
6318: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
6319: // if(ci.bVisible) {
6320: int lines = max(8, REG8(CL) + 1);
6321: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
6322: // }
6323: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 6324: }
6325:
6326: inline void pcbios_int_10h_02h()
6327: {
1.1.1.14 root 6328: // continuously setting the cursor effectively stops it blinking
6329: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 6330: COORD co;
6331: co.X = REG8(DL);
1.1.1.14 root 6332: co.Y = REG8(DH) + scr_top;
6333:
6334: // some programs hide the cursor by moving it off screen
6335: static bool hidden = false;
1.1.1.23 root 6336: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6337: CONSOLE_CURSOR_INFO ci;
6338: GetConsoleCursorInfo(hStdout, &ci);
6339:
6340: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
6341: if(ci.bVisible) {
6342: ci.bVisible = FALSE;
6343: // SetConsoleCursorInfo(hStdout, &ci);
6344: hidden = true;
6345: }
6346: } else if(hidden) {
6347: if(!ci.bVisible) {
6348: ci.bVisible = TRUE;
6349: // SetConsoleCursorInfo(hStdout, &ci);
6350: }
6351: hidden = false;
6352: }
1.1 root 6353: }
1.1.1.14 root 6354: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
6355: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 6356: }
6357:
6358: inline void pcbios_int_10h_03h()
6359: {
1.1.1.14 root 6360: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6361: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6362: REG8(CL) = mem[0x460];
6363: REG8(CH) = mem[0x461];
6364: }
6365:
6366: inline void pcbios_int_10h_05h()
6367: {
1.1.1.14 root 6368: if(REG8(AL) >= vram_pages) {
6369: return;
6370: }
6371: if(mem[0x462] != REG8(AL)) {
6372: vram_flush();
6373:
1.1.1.23 root 6374: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6375: SMALL_RECT rect;
1.1.1.14 root 6376: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6377: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6378:
1.1.1.16 root 6379: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 6380: for(int x = 0; x < scr_width; x++) {
6381: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6382: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6383: }
6384: }
1.1.1.16 root 6385: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 6386: for(int x = 0; x < scr_width; x++) {
6387: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
6388: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 6389: }
6390: }
1.1.1.14 root 6391: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6392:
6393: COORD co;
1.1.1.14 root 6394: co.X = mem[0x450 + REG8(AL) * 2];
6395: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
6396: if(co.Y < scr_top + scr_height) {
6397: SetConsoleCursorPosition(hStdout, co);
6398: }
1.1 root 6399: }
1.1.1.14 root 6400: mem[0x462] = REG8(AL);
6401: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
6402: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 6403: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 6404: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 6405: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 6406: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 6407: }
6408:
6409: inline void pcbios_int_10h_06h()
6410: {
1.1.1.14 root 6411: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6412: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6413: return;
6414: }
6415: vram_flush();
6416:
1.1.1.23 root 6417: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6418: SMALL_RECT rect;
1.1.1.14 root 6419: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6420: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6421:
6422: int right = min(REG8(DL), scr_width - 1);
6423: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6424:
6425: if(REG8(AL) == 0) {
1.1.1.14 root 6426: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6427: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6428: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6429: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6430: }
6431: }
6432: } else {
1.1.1.14 root 6433: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 6434: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6435: if(y2 <= bottom) {
6436: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6437: } else {
1.1.1.14 root 6438: SCR_BUF(y,x).Char.AsciiChar = ' ';
6439: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6440: }
1.1.1.14 root 6441: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6442: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6443: }
6444: }
6445: }
1.1.1.14 root 6446: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6447: }
6448:
6449: inline void pcbios_int_10h_07h()
6450: {
1.1.1.14 root 6451: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6452: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6453: return;
6454: }
6455: vram_flush();
6456:
1.1.1.23 root 6457: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6458: SMALL_RECT rect;
1.1.1.14 root 6459: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6460: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6461:
6462: int right = min(REG8(DL), scr_width - 1);
6463: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6464:
6465: if(REG8(AL) == 0) {
1.1.1.14 root 6466: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6467: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6468: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6469: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6470: }
6471: }
6472: } else {
1.1.1.14 root 6473: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 6474: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6475: if(y2 >= REG8(CH)) {
6476: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6477: } else {
1.1.1.14 root 6478: SCR_BUF(y,x).Char.AsciiChar = ' ';
6479: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6480: }
1.1.1.14 root 6481: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6482: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6483: }
6484: }
6485: }
1.1.1.14 root 6486: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6487: }
6488:
6489: inline void pcbios_int_10h_08h()
6490: {
6491: COORD co;
6492: DWORD num;
6493:
1.1.1.14 root 6494: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6495: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6496:
6497: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6498: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6499: co.Y += scr_top;
6500: vram_flush();
1.1 root 6501: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
6502: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
6503: REG8(AL) = scr_char[0];
6504: REG8(AH) = scr_attr[0];
6505: } else {
1.1.1.16 root 6506: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 6507: }
6508: }
6509:
6510: inline void pcbios_int_10h_09h()
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: write_text_vram_attr(dest - vram, REG8(BL));
6529: mem[dest++] = REG8(BL);
1.1 root 6530: }
1.1.1.35 root 6531: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6532: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6533: #endif
1.1 root 6534: } else {
1.1.1.14 root 6535: while(dest < end) {
1.1 root 6536: mem[dest++] = REG8(AL);
6537: mem[dest++] = REG8(BL);
6538: }
6539: }
6540: }
6541:
6542: inline void pcbios_int_10h_0ah()
6543: {
6544: COORD co;
6545:
1.1.1.14 root 6546: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6547: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6548:
1.1.1.16 root 6549: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6550: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6551:
6552: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6553: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6554: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6555: #endif
1.1.1.16 root 6556: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6557: while(dest < end) {
6558: write_text_vram_char(dest - vram, REG8(AL));
6559: mem[dest++] = REG8(AL);
6560: dest++;
1.1 root 6561: }
1.1.1.35 root 6562: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6563: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6564: #endif
1.1 root 6565: } else {
1.1.1.14 root 6566: while(dest < end) {
1.1 root 6567: mem[dest++] = REG8(AL);
6568: dest++;
6569: }
6570: }
6571: }
6572:
6573: inline void pcbios_int_10h_0eh()
6574: {
1.1.1.14 root 6575: DWORD num;
6576: COORD co;
6577:
6578: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6579: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6580:
6581: if(REG8(AL) == 7) {
6582: //MessageBeep(-1);
6583: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
6584: if(REG8(AL) == 10) {
6585: vram_flush();
6586: }
1.1.1.23 root 6587: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 6588: cursor_moved = true;
6589: } else {
1.1.1.16 root 6590: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 6591: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6592: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6593: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6594: #endif
1.1.1.16 root 6595: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6596: write_text_vram_char(dest - vram, REG8(AL));
1.1.1.35 root 6597: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6598: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6599: #endif
1.1.1.14 root 6600:
1.1.1.23 root 6601: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6602: if(++co.X == scr_width) {
6603: co.X = 0;
6604: if(++co.Y == scr_height) {
6605: vram_flush();
6606: WriteConsole(hStdout, "\n", 1, &num, NULL);
6607: cursor_moved = true;
6608: }
6609: }
6610: if(!cursor_moved) {
6611: co.Y += scr_top;
6612: SetConsoleCursorPosition(hStdout, co);
6613: cursor_moved = true;
6614: }
6615: }
6616: mem[dest] = REG8(AL);
6617: }
1.1 root 6618: }
6619:
6620: inline void pcbios_int_10h_0fh()
6621: {
6622: REG8(AL) = mem[0x449];
6623: REG8(AH) = mem[0x44a];
6624: REG8(BH) = mem[0x462];
6625: }
6626:
1.1.1.14 root 6627: inline void pcbios_int_10h_11h()
6628: {
6629: switch(REG8(AL)) {
1.1.1.16 root 6630: case 0x01:
1.1.1.14 root 6631: case 0x11:
1.1.1.16 root 6632: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 6633: break;
1.1.1.16 root 6634: case 0x02:
1.1.1.14 root 6635: case 0x12:
1.1.1.16 root 6636: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6637: break;
1.1.1.16 root 6638: case 0x04:
1.1.1.14 root 6639: case 0x14:
1.1.1.16 root 6640: pcbios_set_console_size(80, 25, true);
6641: break;
6642: case 0x18:
6643: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6644: break;
6645: case 0x30:
6646: SREG(ES) = 0;
6647: i386_load_segment_descriptor(ES);
6648: REG16(BP) = 0;
6649: REG16(CX) = mem[0x485];
6650: REG8(DL) = mem[0x484];
6651: break;
6652: }
6653: }
6654:
6655: inline void pcbios_int_10h_12h()
6656: {
1.1.1.16 root 6657: switch(REG8(BL)) {
6658: case 0x10:
1.1.1.14 root 6659: REG16(BX) = 0x0003;
6660: REG16(CX) = 0x0009;
1.1.1.16 root 6661: break;
1.1.1.14 root 6662: }
6663: }
6664:
1.1 root 6665: inline void pcbios_int_10h_13h()
6666: {
1.1.1.3 root 6667: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 6668: COORD co;
6669: DWORD num;
6670:
6671: co.X = REG8(DL);
1.1.1.14 root 6672: co.Y = REG8(DH) + scr_top;
6673:
6674: vram_flush();
1.1 root 6675:
6676: switch(REG8(AL)) {
6677: case 0x00:
6678: case 0x01:
6679: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6680: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6681: CONSOLE_SCREEN_BUFFER_INFO csbi;
6682: GetConsoleScreenBufferInfo(hStdout, &csbi);
6683: SetConsoleCursorPosition(hStdout, co);
6684:
6685: if(csbi.wAttributes != REG8(BL)) {
6686: SetConsoleTextAttribute(hStdout, REG8(BL));
6687: }
1.1.1.14 root 6688: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
6689:
1.1 root 6690: if(csbi.wAttributes != REG8(BL)) {
6691: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
6692: }
6693: if(REG8(AL) == 0x00) {
1.1.1.15 root 6694: if(!restore_console_on_exit) {
6695: GetConsoleScreenBufferInfo(hStdout, &csbi);
6696: scr_top = csbi.srWindow.Top;
6697: }
1.1.1.14 root 6698: co.X = mem[0x450 + REG8(BH) * 2];
6699: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 6700: SetConsoleCursorPosition(hStdout, co);
6701: } else {
6702: cursor_moved = true;
6703: }
6704: } else {
1.1.1.3 root 6705: m_CF = 1;
1.1 root 6706: }
6707: break;
6708: case 0x02:
6709: case 0x03:
6710: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6711: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6712: CONSOLE_SCREEN_BUFFER_INFO csbi;
6713: GetConsoleScreenBufferInfo(hStdout, &csbi);
6714: SetConsoleCursorPosition(hStdout, co);
6715:
6716: WORD wAttributes = csbi.wAttributes;
6717: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
6718: if(wAttributes != mem[ofs + 1]) {
6719: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
6720: wAttributes = mem[ofs + 1];
6721: }
1.1.1.14 root 6722: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 6723: }
6724: if(csbi.wAttributes != wAttributes) {
6725: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
6726: }
6727: if(REG8(AL) == 0x02) {
1.1.1.14 root 6728: co.X = mem[0x450 + REG8(BH) * 2];
6729: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 6730: SetConsoleCursorPosition(hStdout, co);
6731: } else {
6732: cursor_moved = true;
6733: }
6734: } else {
1.1.1.3 root 6735: m_CF = 1;
1.1 root 6736: }
6737: break;
6738: case 0x10:
6739: case 0x11:
6740: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6741: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6742: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
6743: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
6744: for(int i = 0; i < num; i++) {
6745: mem[ofs++] = scr_char[i];
6746: mem[ofs++] = scr_attr[i];
6747: if(REG8(AL) == 0x11) {
6748: mem[ofs++] = 0;
6749: mem[ofs++] = 0;
6750: }
6751: }
6752: } else {
1.1.1.16 root 6753: 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 6754: mem[ofs++] = mem[src++];
6755: mem[ofs++] = mem[src++];
6756: if(REG8(AL) == 0x11) {
6757: mem[ofs++] = 0;
6758: mem[ofs++] = 0;
6759: }
1.1.1.14 root 6760: if(++co.X == scr_width) {
6761: if(++co.Y == scr_height) {
1.1 root 6762: break;
6763: }
6764: co.X = 0;
6765: }
6766: }
6767: }
6768: break;
6769: case 0x20:
6770: case 0x21:
6771: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6772: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6773: int len = min(REG16(CX), scr_width * scr_height);
6774: for(int i = 0; i < len; i++) {
1.1 root 6775: scr_char[i] = mem[ofs++];
6776: scr_attr[i] = mem[ofs++];
6777: if(REG8(AL) == 0x21) {
6778: ofs += 2;
6779: }
6780: }
1.1.1.14 root 6781: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
6782: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 6783: } else {
1.1.1.16 root 6784: 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 6785: mem[dest++] = mem[ofs++];
6786: mem[dest++] = mem[ofs++];
6787: if(REG8(AL) == 0x21) {
6788: ofs += 2;
6789: }
1.1.1.14 root 6790: if(++co.X == scr_width) {
6791: if(++co.Y == scr_height) {
1.1 root 6792: break;
6793: }
6794: co.X = 0;
6795: }
6796: }
6797: }
6798: break;
6799: default:
1.1.1.22 root 6800: 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 6801: m_CF = 1;
1.1 root 6802: break;
6803: }
6804: }
6805:
1.1.1.30 root 6806: inline void pcbios_int_10h_18h()
6807: {
6808: switch(REG8(AL)) {
6809: case 0x00:
6810: case 0x01:
6811: // REG8(AL) = 0x86;
6812: REG8(AL) = 0x00;
6813: break;
6814: default:
6815: 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));
6816: m_CF = 1;
6817: break;
6818: }
6819: }
6820:
1.1.1.14 root 6821: inline void pcbios_int_10h_1ah()
6822: {
6823: switch(REG8(AL)) {
6824: case 0x00:
6825: REG8(AL) = 0x1a;
6826: REG8(BL) = 0x08;
6827: REG8(BH) = 0x00;
6828: break;
6829: default:
1.1.1.22 root 6830: 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 6831: m_CF = 1;
6832: break;
6833: }
6834: }
6835:
1.1 root 6836: inline void pcbios_int_10h_1dh()
6837: {
6838: switch(REG8(AL)) {
6839: case 0x01:
6840: break;
6841: case 0x02:
6842: REG16(BX) = 0;
6843: break;
6844: default:
1.1.1.22 root 6845: 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));
6846: m_CF = 1;
6847: break;
6848: }
6849: }
6850:
6851: inline void pcbios_int_10h_4fh()
6852: {
6853: switch(REG8(AL)) {
6854: case 0x00:
6855: REG8(AH) = 0x02; // not supported
6856: break;
6857: case 0x01:
6858: case 0x02:
6859: case 0x03:
6860: case 0x04:
6861: case 0x05:
6862: case 0x06:
6863: case 0x07:
6864: case 0x08:
6865: case 0x09:
6866: case 0x0a:
6867: case 0x0b:
6868: case 0x0c:
6869: REG8(AH) = 0x01; // failed
6870: break;
6871: default:
6872: 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 6873: m_CF = 1;
1.1 root 6874: break;
6875: }
6876: }
6877:
6878: inline void pcbios_int_10h_82h()
6879: {
6880: static UINT8 mode = 0;
6881:
6882: switch(REG8(AL)) {
1.1.1.22 root 6883: case 0x00:
1.1 root 6884: if(REG8(BL) != 0xff) {
6885: mode = REG8(BL);
6886: }
6887: REG8(AL) = mode;
6888: break;
6889: default:
1.1.1.22 root 6890: 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 6891: m_CF = 1;
1.1 root 6892: break;
6893: }
6894: }
6895:
1.1.1.22 root 6896: inline void pcbios_int_10h_83h()
6897: {
6898: static UINT8 mode = 0;
6899:
6900: switch(REG8(AL)) {
6901: case 0x00:
6902: REG16(AX) = 0; // offset???
6903: SREG(ES) = (SHADOW_BUF_TOP >> 4);
6904: i386_load_segment_descriptor(ES);
6905: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
6906: break;
6907: default:
6908: 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));
6909: m_CF = 1;
6910: break;
6911: }
6912: }
6913:
6914: inline void pcbios_int_10h_90h()
6915: {
6916: REG8(AL) = mem[0x449];
6917: }
6918:
6919: inline void pcbios_int_10h_91h()
6920: {
6921: REG8(AL) = 0x04; // VGA
6922: }
6923:
6924: inline void pcbios_int_10h_efh()
6925: {
6926: REG16(DX) = 0xffff;
6927: }
6928:
1.1 root 6929: inline void pcbios_int_10h_feh()
6930: {
6931: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6932: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 6933: i386_load_segment_descriptor(ES);
1.1.1.8 root 6934: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 6935: }
6936: int_10h_feh_called = true;
6937: }
6938:
6939: inline void pcbios_int_10h_ffh()
6940: {
6941: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 6942: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6943: COORD co;
6944: DWORD num;
6945:
1.1.1.14 root 6946: vram_flush();
6947:
6948: co.X = (REG16(DI) >> 1) % scr_width;
6949: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 6950: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
6951: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 6952: int len;
6953: for(len = 0; ofs < end; len++) {
6954: scr_char[len] = mem[ofs++];
6955: scr_attr[len] = mem[ofs++];
6956: }
6957: co.Y += scr_top;
6958: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
6959: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 6960: }
6961: int_10h_ffh_called = true;
6962: }
6963:
1.1.1.25 root 6964: inline void pcbios_int_14h_00h()
6965: {
1.1.1.29 root 6966: if(REG16(DX) < 4) {
1.1.1.25 root 6967: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
6968: UINT8 selector = sio_read(REG16(DX), 3);
6969: selector &= ~0x3f;
6970: selector |= REG8(AL) & 0x1f;
6971: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
6972: sio_write(REG16(DX), 3, selector | 0x80);
6973: sio_write(REG16(DX), 0, divisor & 0xff);
6974: sio_write(REG16(DX), 1, divisor >> 8);
6975: sio_write(REG16(DX), 3, selector);
6976: REG8(AH) = sio_read(REG16(DX), 5);
6977: REG8(AL) = sio_read(REG16(DX), 6);
6978: } else {
6979: REG8(AH) = 0x80;
6980: }
6981: }
6982:
6983: inline void pcbios_int_14h_01h()
6984: {
1.1.1.29 root 6985: if(REG16(DX) < 4) {
1.1.1.25 root 6986: UINT8 selector = sio_read(REG16(DX), 3);
6987: sio_write(REG16(DX), 3, selector & ~0x80);
6988: sio_write(REG16(DX), 0, REG8(AL));
6989: sio_write(REG16(DX), 3, selector);
6990: REG8(AH) = sio_read(REG16(DX), 5);
6991: } else {
6992: REG8(AH) = 0x80;
6993: }
6994: }
6995:
6996: inline void pcbios_int_14h_02h()
6997: {
1.1.1.29 root 6998: if(REG16(DX) < 4) {
1.1.1.25 root 6999: UINT8 selector = sio_read(REG16(DX), 3);
7000: sio_write(REG16(DX), 3, selector & ~0x80);
7001: REG8(AL) = sio_read(REG16(DX), 0);
7002: sio_write(REG16(DX), 3, selector);
7003: REG8(AH) = sio_read(REG16(DX), 5);
7004: } else {
7005: REG8(AH) = 0x80;
7006: }
7007: }
7008:
7009: inline void pcbios_int_14h_03h()
7010: {
1.1.1.29 root 7011: if(REG16(DX) < 4) {
1.1.1.25 root 7012: REG8(AH) = sio_read(REG16(DX), 5);
7013: REG8(AL) = sio_read(REG16(DX), 6);
7014: } else {
7015: REG8(AH) = 0x80;
7016: }
7017: }
7018:
7019: inline void pcbios_int_14h_04h()
7020: {
1.1.1.29 root 7021: if(REG16(DX) < 4) {
1.1.1.25 root 7022: UINT8 selector = sio_read(REG16(DX), 3);
7023: if(REG8(CH) <= 0x03) {
7024: selector = (selector & ~0x03) | REG8(CH);
7025: }
7026: if(REG8(BL) == 0x00) {
7027: selector &= ~0x04;
7028: } else if(REG8(BL) == 0x01) {
7029: selector |= 0x04;
7030: }
7031: if(REG8(BH) == 0x00) {
7032: selector = (selector & ~0x38) | 0x00;
7033: } else if(REG8(BH) == 0x01) {
7034: selector = (selector & ~0x38) | 0x08;
7035: } else if(REG8(BH) == 0x02) {
7036: selector = (selector & ~0x38) | 0x18;
7037: } else if(REG8(BH) == 0x03) {
7038: selector = (selector & ~0x38) | 0x28;
7039: } else if(REG8(BH) == 0x04) {
7040: selector = (selector & ~0x38) | 0x38;
7041: }
7042: if(REG8(AL) == 0x00) {
7043: selector |= 0x40;
7044: } else if(REG8(AL) == 0x01) {
7045: selector &= ~0x40;
7046: }
7047: if(REG8(CL) <= 0x0b) {
7048: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
7049: UINT16 divisor = 115200 / rate[REG8(CL)];
7050: sio_write(REG16(DX), 3, selector | 0x80);
7051: sio_write(REG16(DX), 0, divisor & 0xff);
7052: sio_write(REG16(DX), 1, divisor >> 8);
7053: }
7054: sio_write(REG16(DX), 3, selector);
7055: REG8(AH) = sio_read(REG16(DX), 5);
7056: REG8(AL) = sio_read(REG16(DX), 6);
7057: } else {
7058: REG8(AH) = 0x80;
7059: }
7060: }
7061:
7062: inline void pcbios_int_14h_05h()
7063: {
1.1.1.29 root 7064: if(REG16(DX) < 4) {
1.1.1.25 root 7065: if(REG8(AL) == 0x00) {
7066: REG8(BL) = sio_read(REG16(DX), 4);
7067: REG8(AH) = sio_read(REG16(DX), 5);
7068: REG8(AL) = sio_read(REG16(DX), 6);
7069: } else if(REG8(AL) == 0x01) {
7070: sio_write(REG16(DX), 4, REG8(BL));
7071: REG8(AH) = sio_read(REG16(DX), 5);
7072: REG8(AL) = sio_read(REG16(DX), 6);
7073: } else {
7074: 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));
7075: }
7076: } else {
7077: REG8(AH) = 0x80;
7078: }
7079: }
7080:
1.1.1.14 root 7081: inline void pcbios_int_15h_10h()
7082: {
1.1.1.22 root 7083: switch(REG8(AL)) {
7084: case 0x00:
1.1.1.14 root 7085: Sleep(10);
1.1.1.35 root 7086: REQUEST_HARDWRE_UPDATE();
1.1.1.22 root 7087: break;
7088: default:
7089: 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 7090: REG8(AH) = 0x86;
7091: m_CF = 1;
7092: }
7093: }
7094:
1.1 root 7095: inline void pcbios_int_15h_23h()
7096: {
7097: switch(REG8(AL)) {
1.1.1.22 root 7098: case 0x00:
1.1.1.8 root 7099: REG8(CL) = cmos_read(0x2d);
7100: REG8(CH) = cmos_read(0x2e);
1.1 root 7101: break;
1.1.1.22 root 7102: case 0x01:
1.1.1.8 root 7103: cmos_write(0x2d, REG8(CL));
7104: cmos_write(0x2e, REG8(CH));
1.1 root 7105: break;
7106: default:
1.1.1.22 root 7107: 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 7108: REG8(AH) = 0x86;
1.1.1.3 root 7109: m_CF = 1;
1.1 root 7110: break;
7111: }
7112: }
7113:
7114: inline void pcbios_int_15h_24h()
7115: {
7116: switch(REG8(AL)) {
1.1.1.22 root 7117: case 0x00:
1.1.1.3 root 7118: i386_set_a20_line(0);
1.1 root 7119: REG8(AH) = 0;
7120: break;
1.1.1.22 root 7121: case 0x01:
1.1.1.3 root 7122: i386_set_a20_line(1);
1.1 root 7123: REG8(AH) = 0;
7124: break;
1.1.1.22 root 7125: case 0x02:
1.1 root 7126: REG8(AH) = 0;
1.1.1.3 root 7127: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 7128: REG16(CX) = 0;
7129: break;
1.1.1.22 root 7130: case 0x03:
1.1 root 7131: REG16(AX) = 0;
7132: REG16(BX) = 0;
7133: break;
1.1.1.22 root 7134: default:
7135: 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));
7136: REG8(AH) = 0x86;
7137: m_CF = 1;
7138: break;
1.1 root 7139: }
7140: }
7141:
7142: inline void pcbios_int_15h_49h()
7143: {
1.1.1.27 root 7144: REG8(AH) = 0x00;
7145: REG8(BL) = 0x00; // DOS/V
1.1 root 7146: }
7147:
1.1.1.22 root 7148: inline void pcbios_int_15h_50h()
7149: {
7150: switch(REG8(AL)) {
7151: case 0x00:
7152: case 0x01:
7153: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
7154: REG8(AH) = 0x01; // invalid font type in bh
7155: m_CF = 1;
1.1.1.27 root 7156: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 7157: REG8(AH) = 0x02; // bl not zero
7158: m_CF = 1;
7159: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
7160: REG8(AH) = 0x04; // invalid code page
7161: m_CF = 1;
1.1.1.27 root 7162: } else if(REG8(AL) == 0x01) {
7163: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 7164: m_CF = 1;
1.1.1.27 root 7165: } else {
7166: // dummy font read routine is at fffd:000d
7167: SREG(ES) = 0xfffd;
7168: i386_load_segment_descriptor(ES);
1.1.1.32 root 7169: REG16(BX) = 0x000d;
1.1.1.27 root 7170: REG8(AH) = 0x00; // success
1.1.1.22 root 7171: }
7172: break;
7173: default:
7174: 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));
7175: REG8(AH) = 0x86;
7176: m_CF = 1;
7177: break;
7178: }
7179: }
7180:
1.1.1.30 root 7181: inline void pcbios_int_15h_53h()
7182: {
7183: switch(REG8(AL)) {
7184: case 0x00:
7185: // APM is not installed
7186: REG8(AH) = 0x86;
7187: m_CF = 1;
7188: break;
7189: default:
7190: 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));
7191: REG8(AH) = 0x86;
7192: m_CF = 1;
7193: break;
7194: }
7195: }
7196:
1.1.1.35 root 7197:
7198: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID)
1.1 root 7199: {
7200: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 7201: UINT32 msec = usec / 1000;
7202:
1.1.1.35 root 7203: while(msec && !m_halted) {
1.1.1.14 root 7204: UINT32 tmp = min(msec, 100);
7205: if(msec - tmp < 10) {
7206: tmp = msec;
7207: }
7208: Sleep(tmp);
7209: msec -= tmp;
7210: }
1.1.1.35 root 7211:
7212: #ifdef USE_SERVICE_THREAD
7213: service_exit = true;
7214: #endif
7215: return(0);
7216: }
7217:
7218: inline void pcbios_int_15h_86h()
7219: {
7220: if(!(REG16(CX) == 0 && REG16(DX) == 0)) {
7221: #ifdef USE_SERVICE_THREAD
7222: start_service_loop(pcbios_int_15h_86h_thread);
7223: #else
7224: pcbios_int_15h_86h_thread(NULL);
7225: REQUEST_HARDWRE_UPDATE();
7226: #endif
7227: }
1.1 root 7228: }
7229:
7230: inline void pcbios_int_15h_87h()
7231: {
7232: // copy extended memory (from DOSBox)
7233: int len = REG16(CX) * 2;
1.1.1.3 root 7234: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 7235: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
7236: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
7237: memcpy(mem + dst, mem + src, len);
7238: REG16(AX) = 0x00;
7239: }
7240:
7241: inline void pcbios_int_15h_88h()
7242: {
1.1.1.17 root 7243: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 7244: }
7245:
7246: inline void pcbios_int_15h_89h()
7247: {
1.1.1.21 root 7248: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 7249: // switch to protected mode (from DOSBox)
7250: write_io_byte(0x20, 0x10);
7251: write_io_byte(0x21, REG8(BH));
7252: write_io_byte(0x21, 0x00);
7253: write_io_byte(0xa0, 0x10);
7254: write_io_byte(0xa1, REG8(BL));
7255: write_io_byte(0xa1, 0x00);
1.1.1.3 root 7256: i386_set_a20_line(1);
7257: int ofs = SREG_BASE(ES) + REG16(SI);
7258: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
7259: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
7260: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
7261: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
7262: #if defined(HAS_I386)
7263: m_cr[0] |= 1;
7264: #else
7265: m_msw |= 1;
7266: #endif
7267: SREG(DS) = 0x18;
7268: SREG(ES) = 0x20;
7269: SREG(SS) = 0x28;
7270: i386_load_segment_descriptor(DS);
7271: i386_load_segment_descriptor(ES);
7272: i386_load_segment_descriptor(SS);
1.1.1.21 root 7273: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 7274: REG16(SP) += 6;
1.1.1.3 root 7275: #if defined(HAS_I386)
1.1.1.21 root 7276: UINT32 flags = get_flags();
7277: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7278: set_flags(flags);
1.1.1.3 root 7279: #else
1.1.1.21 root 7280: UINT32 flags = CompressFlags();
7281: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7282: ExpandFlags(flags);
1.1.1.3 root 7283: #endif
1.1 root 7284: REG16(AX) = 0x00;
1.1.1.21 root 7285: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 7286: #else
1.1.1.21 root 7287: // i86/i186/v30: protected mode is not supported
1.1 root 7288: REG8(AH) = 0x86;
1.1.1.3 root 7289: m_CF = 1;
1.1 root 7290: #endif
7291: }
7292:
1.1.1.21 root 7293: inline void pcbios_int_15h_8ah()
7294: {
7295: UINT32 size = MAX_MEM - 0x100000;
7296: REG16(AX) = size & 0xffff;
7297: REG16(DX) = size >> 16;
7298: }
7299:
1.1.1.3 root 7300: #if defined(HAS_I386)
1.1 root 7301: inline void pcbios_int_15h_c9h()
7302: {
7303: REG8(AH) = 0x00;
7304: REG8(CH) = cpu_type;
7305: REG8(CL) = cpu_step;
7306: }
1.1.1.3 root 7307: #endif
1.1 root 7308:
7309: inline void pcbios_int_15h_cah()
7310: {
7311: switch(REG8(AL)) {
1.1.1.22 root 7312: case 0x00:
1.1 root 7313: if(REG8(BL) > 0x3f) {
7314: REG8(AH) = 0x03;
1.1.1.3 root 7315: m_CF = 1;
1.1 root 7316: } else if(REG8(BL) < 0x0e) {
7317: REG8(AH) = 0x04;
1.1.1.3 root 7318: m_CF = 1;
1.1 root 7319: } else {
1.1.1.8 root 7320: REG8(CL) = cmos_read(REG8(BL));
1.1 root 7321: }
7322: break;
1.1.1.22 root 7323: case 0x01:
1.1 root 7324: if(REG8(BL) > 0x3f) {
7325: REG8(AH) = 0x03;
1.1.1.3 root 7326: m_CF = 1;
1.1 root 7327: } else if(REG8(BL) < 0x0e) {
7328: REG8(AH) = 0x04;
1.1.1.3 root 7329: m_CF = 1;
1.1 root 7330: } else {
1.1.1.8 root 7331: cmos_write(REG8(BL), REG8(CL));
1.1 root 7332: }
7333: break;
7334: default:
1.1.1.22 root 7335: 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 7336: REG8(AH) = 0x86;
1.1.1.3 root 7337: m_CF = 1;
1.1 root 7338: break;
7339: }
7340: }
7341:
1.1.1.22 root 7342: inline void pcbios_int_15h_e8h()
1.1.1.17 root 7343: {
1.1.1.22 root 7344: switch(REG8(AL)) {
7345: #if defined(HAS_I386)
7346: case 0x01:
7347: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
7348: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
7349: break;
1.1.1.17 root 7350: #endif
1.1.1.22 root 7351: default:
7352: 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));
7353: REG8(AH) = 0x86;
7354: m_CF = 1;
7355: break;
7356: }
7357: }
1.1.1.17 root 7358:
1.1.1.33 root 7359: void pcbios_update_key_code(bool wait)
1.1 root 7360: {
1.1.1.32 root 7361: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 7362: #ifdef USE_SERVICE_THREAD
7363: EnterCriticalSection(&key_buf_crit_sect);
7364: #endif
7365: bool empty = key_buf_char->empty();
7366: #ifdef USE_SERVICE_THREAD
7367: LeaveCriticalSection(&key_buf_crit_sect);
7368: #endif
7369: if(empty) {
1.1.1.32 root 7370: if(!update_key_buffer()) {
1.1.1.33 root 7371: if(wait) {
1.1.1.32 root 7372: Sleep(10);
7373: } else {
7374: maybe_idle();
7375: }
1.1.1.14 root 7376: }
7377: }
1.1.1.34 root 7378: }
7379: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 7380: #ifdef USE_SERVICE_THREAD
7381: EnterCriticalSection(&key_buf_crit_sect);
7382: #endif
1.1.1.32 root 7383: if(key_buf_char->count() != 0) {
1.1.1.35 root 7384: key_code = key_buf_char->read() << 0;
7385: key_code |= key_buf_scan->read() << 8;
7386: key_recv = 0x0000ffff;
1.1.1.32 root 7387: }
7388: if(key_buf_char->count() != 0) {
1.1.1.35 root 7389: key_code |= key_buf_char->read() << 16;
7390: key_code |= key_buf_scan->read() << 24;
1.1.1.33 root 7391: key_recv |= 0xffff0000;
1.1.1.32 root 7392: }
1.1.1.35 root 7393: #ifdef USE_SERVICE_THREAD
7394: LeaveCriticalSection(&key_buf_crit_sect);
7395: #endif
1.1 root 7396: }
7397: }
7398:
1.1.1.35 root 7399: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID)
1.1 root 7400: {
1.1.1.33 root 7401: while(key_recv == 0 && !m_halted) {
7402: pcbios_update_key_code(true);
1.1 root 7403: }
1.1.1.33 root 7404: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
7405: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
7406: if(REG8(AH) == 0x10) {
7407: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
7408: } else {
7409: key_code = ((key_code >> 16) & 0xff00);
7410: }
7411: key_recv >>= 16;
1.1 root 7412: }
7413: }
7414: REG16(AX) = key_code & 0xffff;
7415: key_code >>= 16;
1.1.1.33 root 7416: key_recv >>= 16;
1.1.1.35 root 7417:
7418: #ifdef USE_SERVICE_THREAD
7419: service_exit = true;
7420: #endif
7421: return(0);
7422: }
7423:
7424: inline void pcbios_int_16h_00h()
7425: {
7426: #ifdef USE_SERVICE_THREAD
7427: start_service_loop(pcbios_int_16h_00h_thread);
7428: #else
7429: pcbios_int_16h_00h_thread(NULL);
7430: REQUEST_HARDWRE_UPDATE();
7431: #endif
1.1 root 7432: }
7433:
7434: inline void pcbios_int_16h_01h()
7435: {
1.1.1.33 root 7436: if(key_recv == 0) {
7437: pcbios_update_key_code(false);
1.1.1.5 root 7438: }
1.1.1.33 root 7439: if(key_recv != 0) {
7440: UINT32 key_code_tmp = key_code;
7441: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
7442: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
7443: if(REG8(AH) == 0x11) {
7444: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
7445: } else {
7446: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
7447: }
7448: }
1.1 root 7449: }
1.1.1.5 root 7450: REG16(AX) = key_code_tmp & 0xffff;
1.1.1.3 root 7451: #if defined(HAS_I386)
1.1.1.33 root 7452: m_ZF = 0;
7453: #else
7454: m_ZeroVal = 1;
7455: #endif
7456: } else {
7457: #if defined(HAS_I386)
7458: m_ZF = 1;
1.1.1.3 root 7459: #else
1.1.1.33 root 7460: m_ZeroVal = 0;
1.1.1.3 root 7461: #endif
1.1.1.33 root 7462: }
1.1 root 7463: }
7464:
7465: inline void pcbios_int_16h_02h()
7466: {
7467: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
7468: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
7469: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
7470: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
7471: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
7472: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
7473: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
7474: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
7475: }
7476:
7477: inline void pcbios_int_16h_03h()
7478: {
7479: static UINT16 status = 0;
7480:
7481: switch(REG8(AL)) {
7482: case 0x05:
7483: status = REG16(BX);
7484: break;
7485: case 0x06:
7486: REG16(BX) = status;
7487: break;
7488: default:
1.1.1.3 root 7489: m_CF = 1;
1.1 root 7490: break;
7491: }
7492: }
7493:
7494: inline void pcbios_int_16h_05h()
7495: {
1.1.1.32 root 7496: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 7497: #ifdef USE_SERVICE_THREAD
7498: EnterCriticalSection(&key_buf_crit_sect);
7499: #endif
1.1.1.32 root 7500: key_buf_char->write(REG8(CL));
7501: key_buf_scan->write(REG8(CH));
1.1.1.35 root 7502: #ifdef USE_SERVICE_THREAD
7503: LeaveCriticalSection(&key_buf_crit_sect);
7504: #endif
1.1.1.32 root 7505: }
1.1 root 7506: REG8(AL) = 0x00;
7507: }
7508:
7509: inline void pcbios_int_16h_12h()
7510: {
7511: pcbios_int_16h_02h();
7512:
7513: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
7514: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
7515: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
7516: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
7517: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
7518: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
7519: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
7520: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
7521: }
7522:
7523: inline void pcbios_int_16h_13h()
7524: {
7525: static UINT16 status = 0;
7526:
7527: switch(REG8(AL)) {
7528: case 0x00:
7529: status = REG16(DX);
7530: break;
7531: case 0x01:
7532: REG16(DX) = status;
7533: break;
7534: default:
1.1.1.22 root 7535: 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 7536: m_CF = 1;
1.1 root 7537: break;
7538: }
7539: }
7540:
7541: inline void pcbios_int_16h_14h()
7542: {
7543: static UINT8 status = 0;
7544:
7545: switch(REG8(AL)) {
7546: case 0x00:
7547: case 0x01:
7548: status = REG8(AL);
7549: break;
7550: case 0x02:
7551: REG8(AL) = status;
7552: break;
7553: default:
1.1.1.22 root 7554: 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 7555: m_CF = 1;
1.1 root 7556: break;
7557: }
7558: }
7559:
1.1.1.24 root 7560: inline void pcbios_int_16h_55h()
7561: {
7562: switch(REG8(AL)) {
7563: case 0x00:
7564: // keyboard tsr is not present
7565: break;
7566: case 0xfe:
7567: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
7568: break;
7569: case 0xff:
7570: break;
7571: default:
7572: 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));
7573: m_CF = 1;
7574: break;
7575: }
7576: }
7577:
1.1.1.30 root 7578: inline void pcbios_int_16h_6fh()
7579: {
7580: switch(REG8(AL)) {
7581: case 0x00:
7582: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
7583: break;
7584: default:
7585: 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));
7586: m_CF = 1;
7587: break;
7588: }
7589: }
7590:
1.1 root 7591: inline void pcbios_int_1ah_00h()
7592: {
1.1.1.19 root 7593: pcbios_update_daily_timer_counter(timeGetTime());
7594: REG16(CX) = *(UINT16 *)(mem + 0x46e);
7595: REG16(DX) = *(UINT16 *)(mem + 0x46c);
7596: REG8(AL) = mem[0x470];
7597: mem[0x470] = 0;
1.1 root 7598: }
7599:
7600: inline int to_bcd(int t)
7601: {
7602: int u = (t % 100) / 10;
7603: return (u << 4) | (t % 10);
7604: }
7605:
7606: inline void pcbios_int_1ah_02h()
7607: {
7608: SYSTEMTIME time;
7609:
7610: GetLocalTime(&time);
7611: REG8(CH) = to_bcd(time.wHour);
7612: REG8(CL) = to_bcd(time.wMinute);
7613: REG8(DH) = to_bcd(time.wSecond);
7614: REG8(DL) = 0x00;
7615: }
7616:
7617: inline void pcbios_int_1ah_04h()
7618: {
7619: SYSTEMTIME time;
7620:
7621: GetLocalTime(&time);
7622: REG8(CH) = to_bcd(time.wYear / 100);
7623: REG8(CL) = to_bcd(time.wYear);
7624: REG8(DH) = to_bcd(time.wMonth);
7625: REG8(DL) = to_bcd(time.wDay);
7626: }
7627:
7628: inline void pcbios_int_1ah_0ah()
7629: {
7630: SYSTEMTIME time;
7631: FILETIME file_time;
7632: WORD dos_date, dos_time;
7633:
7634: GetLocalTime(&time);
7635: SystemTimeToFileTime(&time, &file_time);
7636: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
7637: REG16(CX) = dos_date;
7638: }
7639:
7640: // msdos system call
7641:
7642: inline void msdos_int_21h_00h()
7643: {
1.1.1.3 root 7644: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 7645: }
7646:
1.1.1.35 root 7647: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID)
1.1 root 7648: {
7649: REG8(AL) = msdos_getche();
1.1.1.33 root 7650: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7651:
1.1.1.35 root 7652: #ifdef USE_SERVICE_THREAD
7653: service_exit = true;
7654: #endif
7655: return(0);
7656: }
7657:
7658: inline void msdos_int_21h_01h()
7659: {
7660: #ifdef USE_SERVICE_THREAD
7661: start_service_loop(msdos_int_21h_01h_thread);
7662: #else
7663: msdos_int_21h_01h_thread(NULL);
7664: REQUEST_HARDWRE_UPDATE();
7665: #endif
1.1 root 7666: }
7667:
7668: inline void msdos_int_21h_02h()
7669: {
1.1.1.33 root 7670: UINT8 data = REG8(DL);
7671: msdos_putch(data);
7672: REG8(AL) = data;
7673: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7674: }
7675:
7676: inline void msdos_int_21h_03h()
7677: {
7678: REG8(AL) = msdos_aux_in();
7679: }
7680:
7681: inline void msdos_int_21h_04h()
7682: {
7683: msdos_aux_out(REG8(DL));
7684: }
7685:
7686: inline void msdos_int_21h_05h()
7687: {
7688: msdos_prn_out(REG8(DL));
7689: }
7690:
7691: inline void msdos_int_21h_06h()
7692: {
7693: if(REG8(DL) == 0xff) {
7694: if(msdos_kbhit()) {
7695: REG8(AL) = msdos_getch();
1.1.1.3 root 7696: #if defined(HAS_I386)
7697: m_ZF = 0;
7698: #else
7699: m_ZeroVal = 1;
7700: #endif
1.1 root 7701: } else {
7702: REG8(AL) = 0;
1.1.1.3 root 7703: #if defined(HAS_I386)
7704: m_ZF = 1;
7705: #else
7706: m_ZeroVal = 0;
7707: #endif
1.1.1.14 root 7708: maybe_idle();
1.1 root 7709: }
7710: } else {
1.1.1.33 root 7711: UINT8 data = REG8(DL);
7712: msdos_putch(data);
7713: REG8(AL) = data;
1.1 root 7714: }
7715: }
7716:
1.1.1.35 root 7717: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID)
1.1 root 7718: {
7719: REG8(AL) = msdos_getch();
1.1.1.26 root 7720:
1.1.1.35 root 7721: #ifdef USE_SERVICE_THREAD
7722: service_exit = true;
7723: #endif
7724: return(0);
1.1 root 7725: }
7726:
1.1.1.35 root 7727: inline void msdos_int_21h_07h()
7728: {
7729: #ifdef USE_SERVICE_THREAD
7730: start_service_loop(msdos_int_21h_07h_thread);
7731: #else
7732: msdos_int_21h_07h_thread(NULL);
7733: REQUEST_HARDWRE_UPDATE();
7734: #endif
7735: }
7736:
7737: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID)
1.1 root 7738: {
7739: REG8(AL) = msdos_getch();
1.1.1.33 root 7740: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7741:
1.1.1.35 root 7742: #ifdef USE_SERVICE_THREAD
7743: service_exit = true;
7744: #endif
7745: return(0);
7746: }
7747:
7748: inline void msdos_int_21h_08h()
7749: {
7750: #ifdef USE_SERVICE_THREAD
7751: start_service_loop(msdos_int_21h_08h_thread);
7752: #else
7753: msdos_int_21h_08h_thread(NULL);
7754: REQUEST_HARDWRE_UPDATE();
7755: #endif
1.1 root 7756: }
7757:
7758: inline void msdos_int_21h_09h()
7759: {
1.1.1.21 root 7760: msdos_stdio_reopen();
7761:
1.1.1.20 root 7762: process_t *process = msdos_process_info_get(current_psp);
7763: int fd = msdos_psp_get_file_table(1, current_psp);
7764:
1.1.1.14 root 7765: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7766: int len = 0;
1.1 root 7767:
1.1.1.14 root 7768: while(str[len] != '$' && len < 0x10000) {
7769: len++;
7770: }
1.1.1.20 root 7771: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 7772: // stdout is redirected to file
1.1.1.20 root 7773: msdos_write(fd, str, len);
1.1 root 7774: } else {
7775: for(int i = 0; i < len; i++) {
1.1.1.14 root 7776: msdos_putch(str[i]);
1.1 root 7777: }
7778: }
1.1.1.33 root 7779: REG8(AL) = '$';
7780: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7781: }
7782:
1.1.1.35 root 7783: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID)
1.1 root 7784: {
1.1.1.3 root 7785: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 7786: int max = mem[ofs] - 1;
7787: UINT8 *buf = mem + ofs + 2;
7788: int chr, p = 0;
7789:
7790: while((chr = msdos_getch()) != 0x0d) {
1.1.1.33 root 7791: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 7792: p = 0;
1.1.1.33 root 7793: msdos_putch(0x03);
7794: msdos_putch(0x0d);
7795: msdos_putch(0x0a);
1.1.1.26 root 7796: break;
1.1.1.33 root 7797: } else if(ctrl_break_pressed) {
7798: // skip this byte
1.1.1.26 root 7799: } else if(chr == 0x00) {
1.1 root 7800: // skip 2nd byte
7801: msdos_getch();
7802: } else if(chr == 0x08) {
7803: // back space
7804: if(p > 0) {
7805: p--;
1.1.1.20 root 7806: if(msdos_ctrl_code_check(buf[p])) {
1.1.1.34 root 7807: msdos_putch(0x08);
7808: msdos_putch(0x08);
7809: msdos_putch(0x20);
7810: msdos_putch(0x20);
7811: msdos_putch(0x08);
7812: msdos_putch(0x08);
1.1.1.36! root 7813: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
! 7814: p--;
! 7815: msdos_putch(0x08);
! 7816: msdos_putch(0x08);
! 7817: msdos_putch(0x20);
! 7818: msdos_putch(0x20);
! 7819: msdos_putch(0x08);
! 7820: msdos_putch(0x08);
1.1.1.34 root 7821: } else {
7822: msdos_putch(0x08);
7823: msdos_putch(0x20);
7824: msdos_putch(0x08);
7825: }
7826: }
7827: } else if(chr == 0x1b) {
7828: // escape
7829: while(p > 0) {
7830: p--;
7831: if(msdos_ctrl_code_check(buf[p])) {
7832: msdos_putch(0x08);
7833: msdos_putch(0x08);
7834: msdos_putch(0x20);
7835: msdos_putch(0x20);
7836: msdos_putch(0x08);
7837: msdos_putch(0x08);
1.1.1.20 root 7838: } else {
1.1.1.34 root 7839: msdos_putch(0x08);
7840: msdos_putch(0x20);
7841: msdos_putch(0x08);
1.1.1.20 root 7842: }
1.1 root 7843: }
7844: } else if(p < max) {
7845: buf[p++] = chr;
7846: msdos_putch(chr);
7847: }
7848: }
7849: buf[p] = 0x0d;
7850: mem[ofs + 1] = p;
1.1.1.33 root 7851: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7852:
1.1.1.35 root 7853: #ifdef USE_SERVICE_THREAD
7854: service_exit = true;
7855: #endif
7856: return(0);
7857: }
7858:
7859: inline void msdos_int_21h_0ah()
7860: {
7861: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) {
7862: #ifdef USE_SERVICE_THREAD
7863: start_service_loop(msdos_int_21h_0ah_thread);
7864: #else
7865: msdos_int_21h_0ah_thread(NULL);
7866: REQUEST_HARDWRE_UPDATE();
7867: #endif
7868: }
1.1 root 7869: }
7870:
7871: inline void msdos_int_21h_0bh()
7872: {
7873: if(msdos_kbhit()) {
7874: REG8(AL) = 0xff;
7875: } else {
7876: REG8(AL) = 0x00;
1.1.1.14 root 7877: maybe_idle();
1.1 root 7878: }
1.1.1.33 root 7879: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7880: }
7881:
7882: inline void msdos_int_21h_0ch()
7883: {
7884: // clear key buffer
1.1.1.21 root 7885: msdos_stdio_reopen();
7886:
1.1.1.20 root 7887: process_t *process = msdos_process_info_get(current_psp);
7888: int fd = msdos_psp_get_file_table(0, current_psp);
7889:
7890: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 7891: // stdin is redirected to file
7892: } else {
7893: while(msdos_kbhit()) {
7894: msdos_getch();
7895: }
7896: }
7897:
7898: switch(REG8(AL)) {
7899: case 0x01:
7900: msdos_int_21h_01h();
7901: break;
7902: case 0x06:
7903: msdos_int_21h_06h();
7904: break;
7905: case 0x07:
7906: msdos_int_21h_07h();
7907: break;
7908: case 0x08:
7909: msdos_int_21h_08h();
7910: break;
7911: case 0x0a:
7912: msdos_int_21h_0ah();
7913: break;
7914: default:
1.1.1.22 root 7915: // 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));
7916: // REG16(AX) = 0x01;
7917: // m_CF = 1;
1.1 root 7918: break;
7919: }
7920: }
7921:
7922: inline void msdos_int_21h_0dh()
7923: {
7924: }
7925:
7926: inline void msdos_int_21h_0eh()
7927: {
7928: if(REG8(DL) < 26) {
7929: _chdrive(REG8(DL) + 1);
7930: msdos_cds_update(REG8(DL));
1.1.1.23 root 7931: msdos_sda_update(current_psp);
1.1 root 7932: }
7933: REG8(AL) = 26; // zdrive
7934: }
7935:
1.1.1.14 root 7936: inline void msdos_int_21h_0fh()
7937: {
7938: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7939: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7940: char *path = msdos_fcb_path(fcb);
7941: 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 7942:
1.1.1.14 root 7943: if(hFile == INVALID_HANDLE_VALUE) {
7944: REG8(AL) = 0xff;
7945: } else {
7946: REG8(AL) = 0;
7947: fcb->current_block = 0;
7948: fcb->record_size = 128;
7949: fcb->file_size = GetFileSize(hFile, NULL);
7950: fcb->handle = hFile;
7951: fcb->cur_record = 0;
7952: }
7953: }
7954:
7955: inline void msdos_int_21h_10h()
7956: {
7957: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7958: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7959:
7960: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
7961: }
7962:
1.1 root 7963: inline void msdos_int_21h_11h()
7964: {
1.1.1.3 root 7965: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7966: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7967:
7968: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7969: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7970: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
7971: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7972: char *path = msdos_fcb_path(fcb);
7973: WIN32_FIND_DATA fd;
7974:
1.1.1.13 root 7975: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
7976: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7977: FindClose(dtainfo->find_handle);
7978: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7979: }
7980: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7981: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
7982: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7983:
1.1.1.14 root 7984: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7985: dtainfo->allowable_mask &= ~8;
1.1 root 7986: }
1.1.1.14 root 7987: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7988: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7989: !msdos_find_file_has_8dot3name(&fd)) {
7990: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7991: FindClose(dtainfo->find_handle);
7992: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7993: break;
7994: }
7995: }
7996: }
1.1.1.13 root 7997: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7998: if(ext_fcb->flag == 0xff) {
7999: ext_find->flag = 0xff;
8000: memset(ext_find->reserved, 0, 5);
8001: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8002: }
8003: find->drive = _getdrive();
1.1.1.13 root 8004: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 8005: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8006: find->nt_res = 0;
8007: msdos_find_file_conv_local_time(&fd);
8008: find->create_time_ms = 0;
8009: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8010: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8011: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8012: find->cluster_hi = find->cluster_lo = 0;
8013: find->file_size = fd.nFileSizeLow;
8014: REG8(AL) = 0x00;
1.1.1.14 root 8015: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8016: if(ext_fcb->flag == 0xff) {
8017: ext_find->flag = 0xff;
8018: memset(ext_find->reserved, 0, 5);
8019: ext_find->attribute = 8;
8020: }
8021: find->drive = _getdrive();
8022: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
8023: find->attribute = 8;
8024: find->nt_res = 0;
8025: msdos_find_file_conv_local_time(&fd);
8026: find->create_time_ms = 0;
8027: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8028: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8029: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8030: find->cluster_hi = find->cluster_lo = 0;
8031: find->file_size = 0;
1.1.1.14 root 8032: dtainfo->allowable_mask &= ~8;
1.1 root 8033: REG8(AL) = 0x00;
8034: } else {
8035: REG8(AL) = 0xff;
8036: }
8037: }
8038:
8039: inline void msdos_int_21h_12h()
8040: {
1.1.1.3 root 8041: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 8042: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8043:
8044: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 8045: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8046: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
8047: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8048: WIN32_FIND_DATA fd;
8049:
1.1.1.13 root 8050: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
8051: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8052: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 8053: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 8054: !msdos_find_file_has_8dot3name(&fd)) {
8055: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8056: FindClose(dtainfo->find_handle);
8057: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8058: break;
8059: }
8060: }
8061: } else {
1.1.1.13 root 8062: FindClose(dtainfo->find_handle);
8063: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8064: }
8065: }
1.1.1.13 root 8066: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8067: if(ext_fcb->flag == 0xff) {
8068: ext_find->flag = 0xff;
8069: memset(ext_find->reserved, 0, 5);
8070: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8071: }
8072: find->drive = _getdrive();
1.1.1.13 root 8073: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 8074: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8075: find->nt_res = 0;
8076: msdos_find_file_conv_local_time(&fd);
8077: find->create_time_ms = 0;
8078: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8079: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8080: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8081: find->cluster_hi = find->cluster_lo = 0;
8082: find->file_size = fd.nFileSizeLow;
8083: REG8(AL) = 0x00;
1.1.1.14 root 8084: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8085: if(ext_fcb->flag == 0xff) {
8086: ext_find->flag = 0xff;
8087: memset(ext_find->reserved, 0, 5);
8088: ext_find->attribute = 8;
8089: }
8090: find->drive = _getdrive();
8091: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
8092: find->attribute = 8;
8093: find->nt_res = 0;
8094: msdos_find_file_conv_local_time(&fd);
8095: find->create_time_ms = 0;
8096: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8097: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8098: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8099: find->cluster_hi = find->cluster_lo = 0;
8100: find->file_size = 0;
1.1.1.14 root 8101: dtainfo->allowable_mask &= ~8;
1.1 root 8102: REG8(AL) = 0x00;
8103: } else {
8104: REG8(AL) = 0xff;
8105: }
8106: }
8107:
8108: inline void msdos_int_21h_13h()
8109: {
1.1.1.3 root 8110: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 8111: REG8(AL) = 0xff;
8112: } else {
8113: REG8(AL) = 0x00;
8114: }
8115: }
8116:
1.1.1.16 root 8117: inline void msdos_int_21h_14h()
8118: {
8119: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8120: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8121: process_t *process = msdos_process_info_get(current_psp);
8122: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8123: DWORD num = 0;
8124:
8125: memset(mem + dta_laddr, 0, fcb->record_size);
8126: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8127: REG8(AL) = 1;
8128: } else {
8129: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
8130: fcb->current_block = (position & 0xffffff) / fcb->record_size;
8131: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
8132: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
8133: }
8134: }
8135:
8136: inline void msdos_int_21h_15h()
1.1.1.14 root 8137: {
8138: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8139: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 8140: process_t *process = msdos_process_info_get(current_psp);
8141: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8142: DWORD num = 0;
1.1.1.14 root 8143:
1.1.1.16 root 8144: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8145: REG8(AL) = 1;
8146: } else {
8147: fcb->file_size = GetFileSize(fcb->handle, NULL);
8148: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
8149: fcb->current_block = (position & 0xffffff) / fcb->record_size;
8150: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
8151: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
8152: }
8153: }
8154:
8155: inline void msdos_int_21h_16h()
8156: {
8157: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8158: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 8159: char *path = msdos_fcb_path(fcb);
8160: 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 8161:
1.1.1.14 root 8162: if(hFile == INVALID_HANDLE_VALUE) {
8163: REG8(AL) = 0xff;
8164: } else {
8165: REG8(AL) = 0;
8166: fcb->current_block = 0;
8167: fcb->record_size = 128;
8168: fcb->file_size = 0;
8169: fcb->handle = hFile;
8170: fcb->cur_record = 0;
8171: }
8172: }
8173:
1.1.1.16 root 8174: inline void msdos_int_21h_17h()
8175: {
8176: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8177: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
8178: char *path_src = msdos_fcb_path(fcb_src);
8179: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
8180: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
8181: char *path_dst = msdos_fcb_path(fcb_dst);
8182:
8183: if(rename(path_src, path_dst)) {
8184: REG8(AL) = 0xff;
8185: } else {
8186: REG8(AL) = 0;
8187: }
8188: }
8189:
1.1 root 8190: inline void msdos_int_21h_18h()
8191: {
8192: REG8(AL) = 0x00;
8193: }
8194:
8195: inline void msdos_int_21h_19h()
8196: {
8197: REG8(AL) = _getdrive() - 1;
8198: }
8199:
8200: inline void msdos_int_21h_1ah()
8201: {
8202: process_t *process = msdos_process_info_get(current_psp);
8203:
8204: process->dta.w.l = REG16(DX);
1.1.1.3 root 8205: process->dta.w.h = SREG(DS);
1.1.1.23 root 8206: msdos_sda_update(current_psp);
1.1 root 8207: }
8208:
8209: inline void msdos_int_21h_1bh()
8210: {
8211: int drive_num = _getdrive() - 1;
8212: UINT16 seg, ofs;
8213:
8214: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8215: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8216: REG8(AL) = dpb->highest_sector_num + 1;
8217: REG16(CX) = dpb->bytes_per_sector;
8218: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 8219: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 8220: } else {
8221: REG8(AL) = 0xff;
1.1.1.3 root 8222: m_CF = 1;
1.1 root 8223: }
8224:
8225: }
8226:
8227: inline void msdos_int_21h_1ch()
8228: {
8229: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
8230: UINT16 seg, ofs;
8231:
8232: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8233: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8234: REG8(AL) = dpb->highest_sector_num + 1;
8235: REG16(CX) = dpb->bytes_per_sector;
8236: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 8237: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 8238: } else {
8239: REG8(AL) = 0xff;
1.1.1.3 root 8240: m_CF = 1;
1.1 root 8241: }
8242:
8243: }
8244:
8245: inline void msdos_int_21h_1dh()
8246: {
8247: REG8(AL) = 0;
8248: }
8249:
8250: inline void msdos_int_21h_1eh()
8251: {
8252: REG8(AL) = 0;
8253: }
8254:
8255: inline void msdos_int_21h_1fh()
8256: {
8257: int drive_num = _getdrive() - 1;
8258: UINT16 seg, ofs;
8259:
8260: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8261: REG8(AL) = 0;
1.1.1.3 root 8262: SREG(DS) = seg;
8263: i386_load_segment_descriptor(DS);
1.1 root 8264: REG16(BX) = ofs;
8265: } else {
8266: REG8(AL) = 0xff;
1.1.1.3 root 8267: m_CF = 1;
1.1 root 8268: }
8269: }
8270:
8271: inline void msdos_int_21h_20h()
8272: {
8273: REG8(AL) = 0;
8274: }
8275:
1.1.1.14 root 8276: inline void msdos_int_21h_21h()
8277: {
8278: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8279: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8280:
8281: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8282: REG8(AL) = 1;
8283: } else {
8284: process_t *process = msdos_process_info_get(current_psp);
8285: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8286: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 8287: DWORD num = 0;
1.1.1.14 root 8288: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8289: REG8(AL) = 1;
8290: } else {
8291: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8292: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 8293: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 8294: }
8295: }
8296: }
8297:
8298: inline void msdos_int_21h_22h()
8299: {
8300: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8301: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8302:
8303: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8304: REG8(AL) = 0xff;
8305: } else {
8306: process_t *process = msdos_process_info_get(current_psp);
8307: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 8308: DWORD num = 0;
1.1.1.14 root 8309: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
8310: fcb->file_size = GetFileSize(fcb->handle, NULL);
8311: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8312: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 8313: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 8314: }
8315: }
8316:
1.1.1.16 root 8317: inline void msdos_int_21h_23h()
8318: {
8319: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8320: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8321: char *path = msdos_fcb_path(fcb);
8322: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
8323:
8324: if(hFile == INVALID_HANDLE_VALUE) {
8325: REG8(AL) = 0xff;
8326: } else {
8327: UINT32 size = GetFileSize(hFile, NULL);
8328: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
8329: REG8(AL) = 0;
8330: }
8331: }
8332:
8333: inline void msdos_int_21h_24h()
8334: {
8335: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8336: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8337:
8338: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
8339: }
8340:
1.1 root 8341: inline void msdos_int_21h_25h()
8342: {
8343: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 8344: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 8345: }
8346:
8347: inline void msdos_int_21h_26h()
8348: {
8349: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
8350:
8351: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
8352: psp->first_mcb = REG16(DX) + 16;
8353: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
8354: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
8355: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
8356: psp->parent_psp = 0;
8357: }
8358:
1.1.1.16 root 8359: inline void msdos_int_21h_27h()
8360: {
8361: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8362: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8363:
8364: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8365: REG8(AL) = 1;
8366: } else {
8367: process_t *process = msdos_process_info_get(current_psp);
8368: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8369: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
8370: DWORD num = 0;
8371: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
8372: REG8(AL) = 1;
8373: } else {
8374: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8375: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
8376: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
8377: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
8378: }
8379: }
8380: }
8381:
8382: inline void msdos_int_21h_28h()
8383: {
8384: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8385: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8386:
8387: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8388: REG8(AL) = 0xff;
8389: } else {
8390: process_t *process = msdos_process_info_get(current_psp);
8391: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8392: DWORD num = 0;
8393: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
8394: fcb->file_size = GetFileSize(fcb->handle, NULL);
8395: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8396: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
8397: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
8398: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
8399: }
8400: }
8401:
1.1 root 8402: inline void msdos_int_21h_29h()
8403: {
1.1.1.20 root 8404: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
8405: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 8406: UINT8 drv = 0;
8407: char sep_chars[] = ":.;,=+";
8408: char end_chars[] = "\\<>|/\"[]";
8409: char spc_chars[] = " \t";
8410:
1.1.1.20 root 8411: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
8412: buffer[1023] = 0;
8413: memset(name, 0x20, sizeof(name));
8414: memset(ext, 0x20, sizeof(ext));
8415:
1.1 root 8416: if(REG8(AL) & 1) {
1.1.1.20 root 8417: ofs += strspn((char *)(buffer + ofs), spc_chars);
8418: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 8419: ofs++;
8420: }
8421: }
1.1.1.20 root 8422: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 8423:
1.1.1.24 root 8424: if(buffer[ofs + 1] == ':') {
8425: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
8426: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 8427: ofs += 2;
1.1.1.24 root 8428: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
8429: ofs++;
8430: }
8431: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
8432: drv = buffer[ofs] - 'A' + 1;
1.1 root 8433: ofs += 2;
1.1.1.24 root 8434: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
8435: ofs++;
8436: }
1.1 root 8437: }
8438: }
1.1.1.20 root 8439: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
8440: UINT8 c = buffer[ofs];
8441: if(is_kanji) {
8442: is_kanji = 0;
8443: } else if(msdos_lead_byte_check(c)) {
8444: is_kanji = 1;
8445: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 8446: break;
8447: } else if(c >= 'a' && c <= 'z') {
8448: c -= 0x20;
8449: }
8450: ofs++;
8451: name[i] = c;
8452: }
1.1.1.20 root 8453: if(buffer[ofs] == '.') {
1.1 root 8454: ofs++;
1.1.1.20 root 8455: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
8456: UINT8 c = buffer[ofs];
8457: if(is_kanji) {
8458: is_kanji = 0;
8459: } else if(msdos_lead_byte_check(c)) {
8460: is_kanji = 1;
8461: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 8462: break;
8463: } else if(c >= 'a' && c <= 'z') {
8464: c -= 0x20;
8465: }
8466: ofs++;
8467: ext[i] = c;
8468: }
8469: }
1.1.1.20 root 8470: int si = REG16(SI) + ofs;
1.1.1.3 root 8471: int ds = SREG(DS);
1.1 root 8472: while(si > 0xffff) {
8473: si -= 0x10;
8474: ds++;
8475: }
8476: REG16(SI) = si;
1.1.1.3 root 8477: SREG(DS) = ds;
8478: i386_load_segment_descriptor(DS);
1.1 root 8479:
1.1.1.3 root 8480: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 8481: if(!(REG8(AL) & 2) || drv != 0) {
8482: fcb[0] = drv;
8483: }
8484: if(!(REG8(AL) & 4) || name[0] != 0x20) {
8485: memcpy(fcb + 1, name, 8);
8486: }
8487: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
8488: memcpy(fcb + 9, ext, 3);
8489: }
8490: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 8491: if(fcb[i] == '*') {
8492: found_star = 1;
8493: }
8494: if(found_star) {
8495: fcb[i] = '?';
8496: }
8497: }
1.1.1.20 root 8498: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 8499: if(fcb[i] == '*') {
8500: found_star = 1;
8501: }
8502: if(found_star) {
8503: fcb[i] = '?';
8504: }
8505: }
8506:
8507: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
8508: if(memchr(fcb + 1, '?', 8 + 3)) {
8509: REG8(AL) = 0x01;
1.1.1.20 root 8510: } else {
8511: REG8(AL) = 0x00;
1.1 root 8512: }
8513: } else {
8514: REG8(AL) = 0xff;
8515: }
8516: }
8517:
8518: inline void msdos_int_21h_2ah()
8519: {
8520: SYSTEMTIME sTime;
8521:
8522: GetLocalTime(&sTime);
8523: REG16(CX) = sTime.wYear;
8524: REG8(DH) = (UINT8)sTime.wMonth;
8525: REG8(DL) = (UINT8)sTime.wDay;
8526: REG8(AL) = (UINT8)sTime.wDayOfWeek;
8527: }
8528:
8529: inline void msdos_int_21h_2bh()
8530: {
1.1.1.14 root 8531: REG8(AL) = 0xff;
1.1 root 8532: }
8533:
8534: inline void msdos_int_21h_2ch()
8535: {
8536: SYSTEMTIME sTime;
8537:
8538: GetLocalTime(&sTime);
8539: REG8(CH) = (UINT8)sTime.wHour;
8540: REG8(CL) = (UINT8)sTime.wMinute;
8541: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 8542: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 8543: }
8544:
8545: inline void msdos_int_21h_2dh()
8546: {
8547: REG8(AL) = 0x00;
8548: }
8549:
8550: inline void msdos_int_21h_2eh()
8551: {
8552: process_t *process = msdos_process_info_get(current_psp);
8553:
8554: process->verify = REG8(AL);
8555: }
8556:
8557: inline void msdos_int_21h_2fh()
8558: {
8559: process_t *process = msdos_process_info_get(current_psp);
8560:
8561: REG16(BX) = process->dta.w.l;
1.1.1.3 root 8562: SREG(ES) = process->dta.w.h;
8563: i386_load_segment_descriptor(ES);
1.1 root 8564: }
8565:
8566: inline void msdos_int_21h_30h()
8567: {
8568: // Version Flag / OEM
1.1.1.27 root 8569: if(REG8(AL) == 0x01) {
1.1.1.29 root 8570: #ifdef SUPPORT_HMA
8571: REG16(BX) = 0x0000;
8572: #else
8573: REG16(BX) = 0x1000; // DOS is in HMA
8574: #endif
1.1 root 8575: } else {
1.1.1.27 root 8576: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
8577: // but this is not correct on Windows 98 SE
8578: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
8579: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 8580: }
1.1.1.27 root 8581: REG16(CX) = 0x0000;
1.1.1.30 root 8582: REG8(AL) = dos_major_version; // 7
8583: REG8(AH) = dos_minor_version; // 10
1.1 root 8584: }
8585:
8586: inline void msdos_int_21h_31h()
8587: {
1.1.1.29 root 8588: try {
8589: msdos_mem_realloc(current_psp, REG16(DX), NULL);
8590: } catch(...) {
8591: // recover the broken mcb
8592: int mcb_seg = current_psp - 1;
8593: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 8594:
1.1.1.29 root 8595: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 8596: mcb->mz = 'M';
8597: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
8598:
1.1.1.29 root 8599: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.33 root 8600: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4));
1.1.1.29 root 8601: } else {
1.1.1.33 root 8602: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0);
1.1.1.29 root 8603: }
8604: } else {
8605: mcb->mz = 'Z';
1.1.1.30 root 8606: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 8607: }
8608: msdos_mem_realloc(current_psp, REG16(DX), NULL);
8609: }
1.1 root 8610: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
8611: }
8612:
8613: inline void msdos_int_21h_32h()
8614: {
8615: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
8616: UINT16 seg, ofs;
8617:
8618: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8619: REG8(AL) = 0;
1.1.1.3 root 8620: SREG(DS) = seg;
8621: i386_load_segment_descriptor(DS);
1.1 root 8622: REG16(BX) = ofs;
8623: } else {
8624: REG8(AL) = 0xff;
1.1.1.3 root 8625: m_CF = 1;
1.1 root 8626: }
8627: }
8628:
8629: inline void msdos_int_21h_33h()
8630: {
8631: char path[MAX_PATH];
8632:
8633: switch(REG8(AL)) {
8634: case 0x00:
1.1.1.33 root 8635: REG8(DL) = ctrl_break_checking;
1.1 root 8636: break;
8637: case 0x01:
1.1.1.33 root 8638: ctrl_break_checking = REG8(DL);
8639: break;
8640: case 0x02:
8641: {
8642: UINT8 old = ctrl_break_checking;
8643: ctrl_break_checking = REG8(DL);
8644: REG8(DL) = old;
8645: }
8646: break;
8647: case 0x03:
8648: case 0x04:
8649: // DOS 4.0+ - Unused
1.1 root 8650: break;
8651: case 0x05:
8652: GetSystemDirectory(path, MAX_PATH);
8653: if(path[0] >= 'a' && path[0] <= 'z') {
8654: REG8(DL) = path[0] - 'a' + 1;
8655: } else {
8656: REG8(DL) = path[0] - 'A' + 1;
8657: }
8658: break;
8659: case 0x06:
1.1.1.2 root 8660: // MS-DOS version (7.10)
1.1 root 8661: REG8(BL) = 7;
1.1.1.2 root 8662: REG8(BH) = 10;
1.1 root 8663: REG8(DL) = 0;
1.1.1.29 root 8664: #ifdef SUPPORT_HMA
8665: REG8(DH) = 0x00;
8666: #else
8667: REG8(DH) = 0x10; // DOS is in HMA
8668: #endif
1.1 root 8669: break;
1.1.1.6 root 8670: case 0x07:
8671: if(REG8(DL) == 0) {
8672: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
8673: } else if(REG8(DL) == 1) {
8674: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
8675: }
8676: break;
1.1 root 8677: default:
1.1.1.22 root 8678: 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 8679: REG16(AX) = 0x01;
1.1.1.3 root 8680: m_CF = 1;
1.1 root 8681: break;
8682: }
8683: }
8684:
1.1.1.23 root 8685: inline void msdos_int_21h_34h()
8686: {
8687: SREG(ES) = SDA_TOP >> 4;
8688: i386_load_segment_descriptor(ES);
8689: REG16(BX) = offsetof(sda_t, indos_flag);;
8690: }
8691:
1.1 root 8692: inline void msdos_int_21h_35h()
8693: {
8694: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 8695: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
8696: i386_load_segment_descriptor(ES);
1.1 root 8697: }
8698:
8699: inline void msdos_int_21h_36h()
8700: {
8701: struct _diskfree_t df = {0};
8702:
8703: if(_getdiskfree(REG8(DL), &df) == 0) {
8704: REG16(AX) = (UINT16)df.sectors_per_cluster;
8705: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 8706: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
8707: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 8708: } else {
8709: REG16(AX) = 0xffff;
8710: }
8711: }
8712:
8713: inline void msdos_int_21h_37h()
8714: {
1.1.1.22 root 8715: static UINT8 dev_flag = 0xff;
1.1 root 8716:
8717: switch(REG8(AL)) {
8718: case 0x00:
1.1.1.22 root 8719: {
8720: process_t *process = msdos_process_info_get(current_psp);
8721: REG8(AL) = 0x00;
8722: REG8(DL) = process->switchar;
8723: }
1.1 root 8724: break;
8725: case 0x01:
1.1.1.22 root 8726: {
8727: process_t *process = msdos_process_info_get(current_psp);
8728: REG8(AL) = 0x00;
8729: process->switchar = REG8(DL);
1.1.1.23 root 8730: msdos_sda_update(current_psp);
1.1.1.22 root 8731: }
8732: break;
8733: case 0x02:
8734: REG8(DL) = dev_flag;
8735: break;
8736: case 0x03:
8737: dev_flag = REG8(DL);
8738: break;
8739: case 0xd0:
8740: case 0xd1:
8741: case 0xd2:
8742: case 0xd3:
8743: case 0xd4:
8744: case 0xd5:
8745: case 0xd6:
8746: case 0xd7:
8747: case 0xdc:
8748: case 0xdd:
8749: case 0xde:
8750: case 0xdf:
8751: // diet ???
8752: REG16(AX) = 1;
1.1 root 8753: break;
8754: default:
1.1.1.22 root 8755: 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 8756: REG16(AX) = 1;
8757: break;
8758: }
8759: }
8760:
1.1.1.19 root 8761: int get_country_info(country_info_t *ci)
1.1.1.17 root 8762: {
8763: char LCdata[80];
8764:
1.1.1.19 root 8765: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 8766: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
8767: ci->currency_dec_digits = atoi(LCdata);
8768: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
8769: ci->currency_format = *LCdata - '0';
8770: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
8771: ci->date_format = *LCdata - '0';
8772: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
8773: memcpy(&ci->currency_symbol, LCdata, 4);
8774: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
8775: *ci->date_sep = *LCdata;
8776: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
8777: *ci->dec_sep = *LCdata;
8778: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
8779: *ci->list_sep = *LCdata;
8780: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
8781: *ci->thou_sep = *LCdata;
8782: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
8783: *ci->time_sep = *LCdata;
8784: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
8785: if(strchr(LCdata, 'H') != NULL) {
8786: ci->time_format = 1;
8787: }
1.1.1.27 root 8788: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 8789: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 8790: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
8791: return atoi(LCdata);
8792: }
8793:
1.1.1.14 root 8794: inline void msdos_int_21h_38h()
8795: {
8796: switch(REG8(AL)) {
8797: case 0x00:
1.1.1.19 root 8798: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 8799: break;
8800: default:
1.1.1.22 root 8801: 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 8802: REG16(AX) = 2;
8803: m_CF = 1;
8804: break;
8805: }
8806: }
8807:
1.1 root 8808: inline void msdos_int_21h_39h(int lfn)
8809: {
1.1.1.3 root 8810: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 8811: REG16(AX) = errno;
1.1.1.3 root 8812: m_CF = 1;
1.1 root 8813: }
8814: }
8815:
8816: inline void msdos_int_21h_3ah(int lfn)
8817: {
1.1.1.3 root 8818: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 8819: REG16(AX) = errno;
1.1.1.3 root 8820: m_CF = 1;
1.1 root 8821: }
8822: }
8823:
8824: inline void msdos_int_21h_3bh(int lfn)
8825: {
1.1.1.3 root 8826: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 8827: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 8828: m_CF = 1;
1.1 root 8829: }
8830: }
8831:
8832: inline void msdos_int_21h_3ch()
8833: {
1.1.1.3 root 8834: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 8835: int attr = GetFileAttributes(path);
1.1.1.29 root 8836: int fd = -1, c;
1.1.1.11 root 8837: UINT16 info;
1.1 root 8838:
1.1.1.11 root 8839: if(msdos_is_con_path(path)) {
8840: fd = _open("CON", _O_WRONLY | _O_BINARY);
8841: info = 0x80d3;
1.1.1.29 root 8842: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8843: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), _O_WRONLY | _O_BINARY)) == -1) {
8844: fd = _open("NUL", _O_WRONLY | _O_BINARY);
8845: }
1.1.1.14 root 8846: info = 0x80d3;
1.1.1.29 root 8847: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8848: fd = _open("NUL", _O_WRONLY | _O_BINARY);
8849: info = 0x80d3;
1.1 root 8850: } else {
8851: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 8852: info = msdos_drive_number(path);
1.1 root 8853: }
8854: if(fd != -1) {
8855: if(attr == -1) {
8856: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
8857: }
8858: SetFileAttributes(path, attr);
8859: REG16(AX) = fd;
1.1.1.11 root 8860: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 8861: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8862: } else {
8863: REG16(AX) = errno;
1.1.1.3 root 8864: m_CF = 1;
1.1 root 8865: }
8866: }
8867:
8868: inline void msdos_int_21h_3dh()
8869: {
1.1.1.3 root 8870: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 8871: int mode = REG8(AL) & 0x03;
1.1.1.29 root 8872: int fd = -1, c;
1.1.1.11 root 8873: UINT16 info;
1.1 root 8874:
8875: if(mode < 0x03) {
1.1.1.11 root 8876: if(msdos_is_con_path(path)) {
1.1.1.13 root 8877: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 8878: info = 0x80d3;
1.1.1.29 root 8879: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8880: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
8881: fd = msdos_open("NUL", file_mode[mode].mode);
8882: }
1.1.1.14 root 8883: info = 0x80d3;
1.1.1.29 root 8884: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8885: fd = msdos_open("NUL", file_mode[mode].mode);
8886: info = 0x80d3;
1.1.1.11 root 8887: } else {
1.1.1.13 root 8888: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 8889: info = msdos_drive_number(path);
8890: }
1.1 root 8891: if(fd != -1) {
8892: REG16(AX) = fd;
1.1.1.11 root 8893: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 8894: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8895: } else {
8896: REG16(AX) = errno;
1.1.1.3 root 8897: m_CF = 1;
1.1 root 8898: }
8899: } else {
8900: REG16(AX) = 0x0c;
1.1.1.3 root 8901: m_CF = 1;
1.1 root 8902: }
8903: }
8904:
8905: inline void msdos_int_21h_3eh()
8906: {
8907: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8908: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8909:
1.1.1.20 root 8910: if(fd < process->max_files && file_handler[fd].valid) {
8911: _close(fd);
8912: msdos_file_handler_close(fd);
8913: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 8914: } else {
8915: REG16(AX) = 0x06;
1.1.1.3 root 8916: m_CF = 1;
1.1 root 8917: }
8918: }
8919:
1.1.1.35 root 8920: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID)
8921: {
8922: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
8923: int max = REG16(CX);
8924: int p = 0;
8925:
8926: while(max > p) {
8927: int chr = msdos_getch();
8928:
8929: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
8930: p = 0;
8931: buf[p++] = 0x0d;
8932: if(max > p) {
8933: buf[p++] = 0x0a;
8934: }
8935: msdos_putch(0x03);
8936: msdos_putch(0x0d);
8937: msdos_putch(0x0a);
8938: break;
8939: } else if(ctrl_break_pressed) {
8940: // skip this byte
8941: } else if(chr == 0x00) {
8942: // skip 2nd byte
8943: msdos_getch();
8944: } else if(chr == 0x0d) {
8945: // carriage return
8946: buf[p++] = 0x0d;
8947: if(max > p) {
8948: buf[p++] = 0x0a;
8949: }
8950: msdos_putch('\n');
8951: break;
8952: } else if(chr == 0x08) {
8953: // back space
8954: if(p > 0) {
8955: p--;
8956: if(msdos_ctrl_code_check(buf[p])) {
8957: msdos_putch(0x08);
8958: msdos_putch(0x08);
8959: msdos_putch(0x20);
8960: msdos_putch(0x20);
8961: msdos_putch(0x08);
8962: msdos_putch(0x08);
1.1.1.36! root 8963: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
! 8964: p--;
! 8965: msdos_putch(0x08);
! 8966: msdos_putch(0x08);
! 8967: msdos_putch(0x20);
! 8968: msdos_putch(0x20);
! 8969: msdos_putch(0x08);
! 8970: msdos_putch(0x08);
1.1.1.35 root 8971: } else {
8972: msdos_putch(0x08);
8973: msdos_putch(0x20);
8974: msdos_putch(0x08);
8975: }
8976: }
8977: } else if(chr == 0x1b) {
8978: // escape
8979: while(p > 0) {
8980: p--;
8981: if(msdos_ctrl_code_check(buf[p])) {
8982: msdos_putch(0x08);
8983: msdos_putch(0x08);
8984: msdos_putch(0x20);
8985: msdos_putch(0x20);
8986: msdos_putch(0x08);
8987: msdos_putch(0x08);
8988: } else {
8989: msdos_putch(0x08);
8990: msdos_putch(0x20);
8991: msdos_putch(0x08);
8992: }
8993: }
8994: } else {
8995: buf[p++] = chr;
8996: msdos_putch(chr);
8997: }
8998: }
8999: REG16(AX) = p;
9000:
9001: #ifdef USE_SERVICE_THREAD
9002: service_exit = true;
9003: #endif
9004: return(0);
9005: }
9006:
1.1 root 9007: inline void msdos_int_21h_3fh()
9008: {
9009: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9010: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9011:
1.1.1.20 root 9012: if(fd < process->max_files && file_handler[fd].valid) {
9013: if(file_mode[file_handler[fd].mode].in) {
9014: if(file_handler[fd].atty) {
1.1 root 9015: // BX is stdin or is redirected to stdin
1.1.1.35 root 9016: if(REG16(CX) != 0) {
9017: #ifdef USE_SERVICE_THREAD
9018: start_service_loop(msdos_int_21h_3fh_thread);
9019: #else
9020: msdos_int_21h_3fh_thread(NULL);
9021: REQUEST_HARDWRE_UPDATE();
9022: #endif
9023: } else {
9024: REG16(AX) = 0;
1.1 root 9025: }
9026: } else {
1.1.1.20 root 9027: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 9028: }
9029: } else {
9030: REG16(AX) = 0x05;
1.1.1.3 root 9031: m_CF = 1;
1.1 root 9032: }
9033: } else {
9034: REG16(AX) = 0x06;
1.1.1.3 root 9035: m_CF = 1;
1.1 root 9036: }
9037: }
9038:
9039: inline void msdos_int_21h_40h()
9040: {
9041: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9042: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9043:
1.1.1.20 root 9044: if(fd < process->max_files && file_handler[fd].valid) {
9045: if(file_mode[file_handler[fd].mode].out) {
1.1 root 9046: if(REG16(CX)) {
1.1.1.20 root 9047: if(file_handler[fd].atty) {
1.1 root 9048: // BX is stdout/stderr or is redirected to stdout
9049: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 9050: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 9051: }
9052: REG16(AX) = REG16(CX);
9053: } else {
1.1.1.20 root 9054: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 9055: }
9056: } else {
1.1.1.20 root 9057: UINT32 pos = _tell(fd);
9058: _lseek(fd, 0, SEEK_END);
9059: UINT32 size = _tell(fd);
1.1.1.12 root 9060: if(pos < size) {
1.1.1.20 root 9061: _lseek(fd, pos, SEEK_SET);
9062: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 9063: } else {
9064: for(UINT32 i = size; i < pos; i++) {
9065: UINT8 tmp = 0;
1.1.1.23 root 9066: msdos_write(fd, &tmp, 1);
1.1.1.12 root 9067: }
1.1.1.20 root 9068: _lseek(fd, pos, SEEK_SET);
1.1 root 9069: }
1.1.1.23 root 9070: REG16(AX) = 0;
1.1 root 9071: }
9072: } else {
9073: REG16(AX) = 0x05;
1.1.1.3 root 9074: m_CF = 1;
1.1 root 9075: }
9076: } else {
9077: REG16(AX) = 0x06;
1.1.1.3 root 9078: m_CF = 1;
1.1 root 9079: }
9080: }
9081:
9082: inline void msdos_int_21h_41h(int lfn)
9083: {
1.1.1.3 root 9084: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 9085: REG16(AX) = errno;
1.1.1.3 root 9086: m_CF = 1;
1.1 root 9087: }
9088: }
9089:
9090: inline void msdos_int_21h_42h()
9091: {
9092: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9093: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9094:
1.1.1.20 root 9095: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 9096: if(REG8(AL) < 0x03) {
1.1.1.35 root 9097: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 9098: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
9099: UINT32 pos = _tell(fd);
1.1 root 9100: REG16(AX) = pos & 0xffff;
9101: REG16(DX) = (pos >> 16);
9102: } else {
9103: REG16(AX) = 0x01;
1.1.1.3 root 9104: m_CF = 1;
1.1 root 9105: }
9106: } else {
9107: REG16(AX) = 0x06;
1.1.1.3 root 9108: m_CF = 1;
1.1 root 9109: }
9110: }
9111:
9112: inline void msdos_int_21h_43h(int lfn)
9113: {
1.1.1.3 root 9114: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 9115: int attr;
9116:
1.1.1.14 root 9117: if(!lfn && REG8(AL) > 2) {
9118: REG16(AX) = 0x01;
9119: m_CF = 1;
9120: return;
9121: }
9122: switch(REG8(lfn ? BL : AL)) {
1.1 root 9123: case 0x00:
9124: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 9125: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
9126: } else {
9127: REG16(AX) = (UINT16)GetLastError();
9128: m_CF = 1;
9129: }
9130: break;
9131: case 0x01:
9132: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
9133: REG16(AX) = (UINT16)GetLastError();
9134: m_CF = 1;
9135: }
9136: break;
9137: case 0x02:
9138: {
9139: DWORD size = GetCompressedFileSize(path, NULL);
9140: if(size != INVALID_FILE_SIZE) {
9141: if(size != 0 && size == GetFileSize(path, NULL)) {
9142: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
9143: // this isn't correct if the file is in the NTFS MFT
9144: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
9145: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
9146: }
9147: }
9148: REG16(AX) = LOWORD(size);
9149: REG16(DX) = HIWORD(size);
9150: } else {
9151: REG16(AX) = (UINT16)GetLastError();
9152: m_CF = 1;
1.1 root 9153: }
1.1.1.14 root 9154: }
9155: break;
9156: case 0x03:
9157: case 0x05:
9158: case 0x07:
9159: {
9160: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9161: if(hFile != INVALID_HANDLE_VALUE) {
9162: FILETIME local, time;
9163: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
9164: if(REG8(BL) == 7) {
9165: ULARGE_INTEGER hund;
9166: hund.LowPart = local.dwLowDateTime;
9167: hund.HighPart = local.dwHighDateTime;
9168: hund.QuadPart += REG16(SI) * 100000;
9169: local.dwLowDateTime = hund.LowPart;
9170: local.dwHighDateTime = hund.HighPart;
9171: }
9172: LocalFileTimeToFileTime(&local, &time);
9173: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
9174: REG8(BL) == 0x05 ? &time : NULL,
9175: REG8(BL) == 0x03 ? &time : NULL)) {
9176: REG16(AX) = (UINT16)GetLastError();
9177: m_CF = 1;
9178: }
9179: CloseHandle(hFile);
9180: } else {
9181: REG16(AX) = (UINT16)GetLastError();
9182: m_CF = 1;
1.1 root 9183: }
1.1.1.14 root 9184: }
9185: break;
9186: case 0x04:
9187: case 0x06:
9188: case 0x08:
9189: {
9190: WIN32_FILE_ATTRIBUTE_DATA fad;
9191: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
9192: FILETIME *time, local;
9193: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
9194: 0x06 ? &fad.ftLastAccessTime :
9195: &fad.ftCreationTime;
9196: FileTimeToLocalFileTime(time, &local);
9197: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
9198: if(REG8(BL) == 0x08) {
9199: ULARGE_INTEGER hund;
9200: hund.LowPart = local.dwLowDateTime;
9201: hund.HighPart = local.dwHighDateTime;
9202: hund.QuadPart /= 100000;
9203: REG16(SI) = (UINT16)(hund.QuadPart % 200);
9204: }
9205: } else {
9206: REG16(AX) = (UINT16)GetLastError();
9207: m_CF = 1;
1.1 root 9208: }
1.1.1.14 root 9209: }
9210: break;
9211: default:
1.1.1.22 root 9212: 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 9213: REG16(AX) = 0x01;
9214: m_CF = 1;
9215: break;
9216: }
9217: }
9218:
9219: inline void msdos_int_21h_44h()
9220: {
1.1.1.22 root 9221: static UINT16 iteration_count = 0;
9222:
1.1.1.20 root 9223: process_t *process = msdos_process_info_get(current_psp);
9224: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9225:
1.1.1.14 root 9226: UINT32 val = DRIVE_NO_ROOT_DIR;
9227:
9228: switch(REG8(AL)) {
9229: case 0x00:
9230: case 0x01:
9231: case 0x02:
9232: case 0x03:
9233: case 0x04:
9234: case 0x05:
9235: case 0x06:
9236: case 0x07:
1.1.1.20 root 9237: if(fd >= process->max_files || !file_handler[fd].valid) {
9238: REG16(AX) = 0x06;
9239: m_CF = 1;
9240: return;
1.1.1.14 root 9241: }
9242: break;
9243: case 0x08:
9244: case 0x09:
9245: if(REG8(BL) >= ('Z' - 'A' + 1)) {
9246: // invalid drive number
9247: REG16(AX) = 0x0f;
9248: m_CF = 1;
9249: return;
9250: } else {
9251: if(REG8(BL) == 0) {
9252: val = GetDriveType(NULL);
9253: } else {
9254: char tmp[8];
9255: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
9256: val = GetDriveType(tmp);
9257: }
9258: if(val == DRIVE_NO_ROOT_DIR) {
9259: // no drive
9260: REG16(AX) = 0x0f;
9261: m_CF = 1;
9262: return;
1.1 root 9263: }
9264: }
9265: break;
9266: }
9267: switch(REG8(AL)) {
9268: case 0x00: // get ioctrl data
1.1.1.20 root 9269: REG16(DX) = file_handler[fd].info;
1.1 root 9270: break;
9271: case 0x01: // set ioctrl data
1.1.1.20 root 9272: file_handler[fd].info |= REG8(DL);
1.1 root 9273: break;
9274: case 0x02: // recv from character device
9275: case 0x03: // send to character device
9276: case 0x04: // recv from block device
9277: case 0x05: // send to block device
9278: REG16(AX) = 0x05;
1.1.1.3 root 9279: m_CF = 1;
1.1 root 9280: break;
9281: case 0x06: // get read status
1.1.1.20 root 9282: if(file_mode[file_handler[fd].mode].in) {
9283: if(file_handler[fd].atty) {
1.1.1.14 root 9284: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 9285: } else {
1.1.1.20 root 9286: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 9287: }
1.1.1.14 root 9288: } else {
9289: REG8(AL) = 0x00;
1.1 root 9290: }
9291: break;
9292: case 0x07: // get write status
1.1.1.20 root 9293: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 9294: REG8(AL) = 0xff;
9295: } else {
9296: REG8(AL) = 0x00;
1.1 root 9297: }
9298: break;
9299: case 0x08: // check removable drive
1.1.1.14 root 9300: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
9301: // removable drive
9302: REG16(AX) = 0x00;
1.1 root 9303: } else {
1.1.1.14 root 9304: // fixed drive
9305: REG16(AX) = 0x01;
1.1 root 9306: }
9307: break;
9308: case 0x09: // check remote drive
1.1.1.14 root 9309: if(val == DRIVE_REMOTE) {
9310: // remote drive
9311: REG16(DX) = 0x1000;
1.1 root 9312: } else {
1.1.1.14 root 9313: // local drive
9314: REG16(DX) = 0x00;
1.1 root 9315: }
9316: break;
1.1.1.21 root 9317: case 0x0a: // check remote handle
9318: REG16(DX) = 0x00; // FIXME
9319: break;
1.1 root 9320: case 0x0b: // set retry count
9321: break;
1.1.1.22 root 9322: case 0x0c: // generic character device request
9323: if(REG8(CL) == 0x45) {
9324: // set iteration (retry) count
9325: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
9326: } else if(REG8(CL) == 0x4a) {
9327: // select code page
9328: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
9329: msdos_nls_tables_update();
9330: } else if(REG8(CL) == 0x65) {
9331: // get iteration (retry) count
9332: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
9333: } else if(REG8(CL) == 0x6a) {
9334: // query selected code page
9335: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
9336: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
9337:
9338: CPINFO info;
9339: GetCPInfo(active_code_page, &info);
9340:
9341: if(info.MaxCharSize != 1) {
9342: for(int i = 0;; i++) {
9343: UINT8 lo = info.LeadByte[2 * i + 0];
9344: UINT8 hi = info.LeadByte[2 * i + 1];
9345:
9346: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
9347: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
9348: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
9349:
9350: if(lo == 0 && hi == 0) {
9351: break;
9352: }
9353: }
9354: }
9355: } else if(REG8(CL) == 0x7f) {
9356: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
9357: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
9358: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
9359: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
9360: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
9361: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
9362: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
9363: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
9364: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
9365: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
9366: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
9367: } else {
9368: 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));
9369: REG16(AX) = 0x01; // invalid function
9370: m_CF = 1;
9371: }
9372: break;
9373: case 0x0d: // generic block device request
9374: if(REG8(CL) == 0x40) {
9375: // set device parameters
9376: } else if(REG8(CL) == 0x46) {
9377: // set volume serial number
9378: } else if(REG8(CL) == 0x4a) {
9379: // lock logical volume
9380: } else if(REG8(CL) == 0x4b) {
9381: // lock physical volume
9382: } else if(REG8(CL) == 0x60) {
9383: // get device parameters
9384: char dev[] = "\\\\.\\A:";
9385: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
9386:
9387: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9388: if(hFile != INVALID_HANDLE_VALUE) {
9389: DISK_GEOMETRY geo;
9390: DWORD dwSize;
9391: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
9392: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
9393: switch(geo.MediaType) {
9394: case F5_360_512:
9395: case F5_320_512:
9396: case F5_320_1024:
9397: case F5_180_512:
9398: case F5_160_512:
9399: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
9400: break;
9401: case F5_1Pt2_512:
9402: case F3_1Pt2_512:
9403: case F3_1Pt23_1024:
9404: case F5_1Pt23_1024:
9405: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
9406: break;
9407: case F3_720_512:
9408: case F3_640_512:
9409: case F5_640_512:
9410: case F5_720_512:
9411: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
9412: break;
9413: case F8_256_128:
9414: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
9415: break;
9416: case FixedMedia:
9417: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
9418: break;
9419: case F3_1Pt44_512:
9420: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
9421: break;
9422: case F3_2Pt88_512:
9423: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
9424: break;
9425: default:
9426: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
9427: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
9428: break;
9429: }
9430: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
9431: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
9432: switch(geo.MediaType) {
9433: case F5_360_512:
9434: case F5_320_512:
9435: case F5_320_1024:
9436: case F5_180_512:
9437: case F5_160_512:
9438: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
9439: break;
9440: default:
9441: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
9442: break;
9443: }
9444: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
9445: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
9446: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
9447: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
9448: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
9449: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
9450: switch(geo.MediaType) {
9451: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
9452: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
9453: break;
9454: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
9455: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
9456: break;
9457: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
9458: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
9459: break;
9460: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
9461: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
9462: break;
9463: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
9464: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
9465: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
9466: break;
9467: case FixedMedia: // hard disk
9468: case RemovableMedia:
9469: case Unknown:
9470: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
9471: break;
9472: default:
9473: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
9474: break;
9475: }
9476: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
9477: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
9478: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
9479: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
9480: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
9481: // 21h BYTE device type
9482: // 22h WORD device attributes (removable or not, etc)
9483: } else {
9484: REG16(AX) = 0x0f; // invalid drive
9485: m_CF = 1;
9486: }
9487: CloseHandle(hFile);
9488: } else {
9489: REG16(AX) = 0x0f; // invalid drive
9490: m_CF = 1;
9491: }
9492: } else if(REG8(CL) == 0x66) {
9493: // get volume serial number
9494: char path[] = "A:\\";
9495: char volume_label[MAX_PATH];
9496: DWORD serial_number = 0;
9497: char file_system[MAX_PATH];
9498:
9499: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
9500:
9501: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
9502: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
9503: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
9504: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
9505: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
9506: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
9507: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
9508: } else {
9509: REG16(AX) = 0x0f; // invalid drive
9510: m_CF = 1;
9511: }
9512: } else if(REG8(CL) == 0x67) {
9513: // get access flag
9514: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
9515: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
9516: } else if(REG8(CL) == 0x68) {
9517: // sense media type
9518: char dev[64];
9519: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9520:
9521: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9522: if(hFile != INVALID_HANDLE_VALUE) {
9523: DISK_GEOMETRY geo;
9524: DWORD dwSize;
9525: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
9526: switch(geo.MediaType) {
9527: case F3_720_512:
9528: case F5_720_512:
9529: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9530: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
9531: break;
9532: case F3_1Pt44_512:
9533: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9534: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
9535: break;
9536: case F3_2Pt88_512:
9537: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9538: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
9539: break;
9540: default:
9541: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
9542: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
9543: break;
9544: }
9545: } else {
9546: REG16(AX) = 0x0f; // invalid drive
9547: m_CF = 1;
9548: }
9549: CloseHandle(hFile);
9550: } else {
9551: REG16(AX) = 0x0f; // invalid drive
9552: m_CF = 1;
9553: }
9554: } else if(REG8(CL) == 0x6a) {
9555: // unlock logical volume
9556: } else if(REG8(CL) == 0x6b) {
9557: // unlock physical volume
9558: } else {
9559: 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));
9560: REG16(AX) = 0x01; // invalid function
9561: m_CF = 1;
9562: }
9563: break;
9564: case 0x0e: // get logical drive map
9565: {
9566: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9567: if(!(GetLogicalDrives() & bits)) {
9568: REG16(AX) = 0x0f; // invalid drive
9569: m_CF = 1;
9570: } else {
9571: REG8(AL) = 0;
9572: }
9573: }
9574: break;
9575: case 0x0f: // set logical drive map
9576: {
9577: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9578: if(!(GetLogicalDrives() & bits)) {
9579: REG16(AX) = 0x0f; // invalid drive
9580: m_CF = 1;
9581: }
9582: }
9583: break;
9584: case 0x10: // query generic ioctrl capability (handle)
9585: switch(REG8(CL)) {
9586: case 0x45:
9587: case 0x4a:
9588: case 0x65:
9589: case 0x6a:
9590: case 0x7f:
9591: REG16(AX) = 0x0000; // supported
9592: break;
9593: default:
9594: REG8(AL) = 0x01; // ioctl capability not available
9595: m_CF = 1;
9596: break;
9597: }
9598: break;
9599: case 0x11: // query generic ioctrl capability (drive)
9600: switch(REG8(CL)) {
9601: case 0x40:
9602: case 0x46:
9603: case 0x4a:
9604: case 0x4b:
9605: case 0x60:
9606: case 0x66:
9607: case 0x67:
9608: case 0x68:
9609: case 0x6a:
9610: case 0x6b:
9611: REG16(AX) = 0x0000; // supported
9612: break;
9613: default:
9614: REG8(AL) = 0x01; // ioctl capability not available
9615: m_CF = 1;
9616: break;
9617: }
9618: break;
9619: case 0x12: // determine dos type
9620: case 0x51: // concurrent dos v3.2+ - installation check
9621: case 0x52: // determine dos type/get dr dos versuin
9622: REG16(AX) = 0x01; // this is not DR-DOS
9623: m_CF = 1;
9624: break;
1.1 root 9625: default:
1.1.1.22 root 9626: 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 9627: REG16(AX) = 0x01;
1.1.1.3 root 9628: m_CF = 1;
1.1 root 9629: break;
9630: }
9631: }
9632:
9633: inline void msdos_int_21h_45h()
9634: {
9635: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9636: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9637:
1.1.1.20 root 9638: if(fd < process->max_files && file_handler[fd].valid) {
9639: int dup_fd = _dup(fd);
9640: if(dup_fd != -1) {
9641: REG16(AX) = dup_fd;
9642: msdos_file_handler_dup(dup_fd, fd, current_psp);
9643: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
9644: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 9645: } else {
9646: REG16(AX) = errno;
1.1.1.3 root 9647: m_CF = 1;
1.1 root 9648: }
9649: } else {
9650: REG16(AX) = 0x06;
1.1.1.3 root 9651: m_CF = 1;
1.1 root 9652: }
9653: }
9654:
9655: inline void msdos_int_21h_46h()
9656: {
9657: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9658: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9659: int dup_fd = REG16(CX);
9660: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 9661:
1.1.1.20 root 9662: if(REG16(BX) == REG16(CX)) {
9663: REG16(AX) = 0x06;
9664: m_CF = 1;
9665: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
9666: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
9667: _close(tmp_fd);
9668: msdos_file_handler_close(tmp_fd);
9669: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
9670: }
9671: if(_dup2(fd, dup_fd) != -1) {
9672: msdos_file_handler_dup(dup_fd, fd, current_psp);
9673: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
9674: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 9675: } else {
9676: REG16(AX) = errno;
1.1.1.3 root 9677: m_CF = 1;
1.1 root 9678: }
9679: } else {
9680: REG16(AX) = 0x06;
1.1.1.3 root 9681: m_CF = 1;
1.1 root 9682: }
9683: }
9684:
9685: inline void msdos_int_21h_47h(int lfn)
9686: {
9687: char path[MAX_PATH];
9688:
9689: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
9690: if(path[1] == ':') {
9691: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 9692: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 9693: } else {
1.1.1.3 root 9694: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 9695: }
9696: } else {
9697: REG16(AX) = errno;
1.1.1.3 root 9698: m_CF = 1;
1.1 root 9699: }
9700: }
9701:
9702: inline void msdos_int_21h_48h()
9703: {
1.1.1.19 root 9704: int seg, umb_linked;
1.1 root 9705:
1.1.1.8 root 9706: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 9707: // unlink umb not to allocate memory in umb
9708: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
9709: msdos_mem_unlink_umb();
9710: }
1.1.1.8 root 9711: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
9712: REG16(AX) = seg;
9713: } else {
9714: REG16(AX) = 0x08;
9715: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
9716: m_CF = 1;
9717: }
1.1.1.19 root 9718: if(umb_linked != 0) {
9719: msdos_mem_link_umb();
9720: }
1.1.1.8 root 9721: } else if((malloc_strategy & 0xf0) == 0x40) {
9722: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
9723: REG16(AX) = seg;
9724: } else {
9725: REG16(AX) = 0x08;
9726: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9727: m_CF = 1;
9728: }
9729: } else if((malloc_strategy & 0xf0) == 0x80) {
9730: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
9731: REG16(AX) = seg;
9732: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
9733: REG16(AX) = seg;
9734: } else {
9735: REG16(AX) = 0x08;
9736: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
9737: m_CF = 1;
9738: }
1.1 root 9739: }
9740: }
9741:
9742: inline void msdos_int_21h_49h()
9743: {
1.1.1.14 root 9744: int mcb_seg = SREG(ES) - 1;
9745: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9746:
9747: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9748: msdos_mem_free(SREG(ES));
9749: } else {
1.1.1.33 root 9750: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 9751: m_CF = 1;
9752: }
1.1 root 9753: }
9754:
9755: inline void msdos_int_21h_4ah()
9756: {
1.1.1.14 root 9757: int mcb_seg = SREG(ES) - 1;
9758: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 9759: int max_paragraphs;
9760:
1.1.1.14 root 9761: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9762: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
9763: REG16(AX) = 0x08;
9764: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
9765: m_CF = 1;
9766: }
9767: } else {
1.1.1.33 root 9768: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 9769: m_CF = 1;
1.1 root 9770: }
9771: }
9772:
9773: inline void msdos_int_21h_4bh()
9774: {
1.1.1.3 root 9775: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
9776: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 9777:
9778: switch(REG8(AL)) {
9779: case 0x00:
9780: case 0x01:
9781: if(msdos_process_exec(command, param, REG8(AL))) {
9782: REG16(AX) = 0x02;
1.1.1.3 root 9783: m_CF = 1;
1.1 root 9784: }
9785: break;
1.1.1.14 root 9786: case 0x03:
9787: {
9788: int fd;
9789: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
9790: REG16(AX) = 0x02;
9791: m_CF = 1;
9792: break;
9793: }
9794: int size = _read(fd, file_buffer, sizeof(file_buffer));
9795: _close(fd);
9796:
9797: UINT16 *overlay = (UINT16 *)param;
9798:
9799: // check exe header
9800: exe_header_t *header = (exe_header_t *)file_buffer;
9801: int header_size = 0;
9802: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
9803: header_size = header->header_size * 16;
9804: // relocation
9805: int start_seg = overlay[1];
9806: for(int i = 0; i < header->relocations; i++) {
9807: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
9808: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
9809: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
9810: }
9811: }
9812: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
9813: }
9814: break;
1.1 root 9815: default:
1.1.1.22 root 9816: 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 9817: REG16(AX) = 0x01;
1.1.1.3 root 9818: m_CF = 1;
1.1 root 9819: break;
9820: }
9821: }
9822:
9823: inline void msdos_int_21h_4ch()
9824: {
9825: msdos_process_terminate(current_psp, REG8(AL), 1);
9826: }
9827:
9828: inline void msdos_int_21h_4dh()
9829: {
9830: REG16(AX) = retval;
9831: }
9832:
9833: inline void msdos_int_21h_4eh()
9834: {
9835: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9836: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9837: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 9838: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 9839: WIN32_FIND_DATA fd;
9840:
1.1.1.14 root 9841: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
9842: find->find_magic = FIND_MAGIC;
9843: find->dta_index = dtainfo - dtalist;
1.1 root 9844: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 9845: dtainfo->allowable_mask = REG8(CL);
9846: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 9847:
1.1.1.14 root 9848: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
9849: dtainfo->allowable_mask &= ~8;
1.1 root 9850: }
1.1.1.14 root 9851: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
9852: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9853: !msdos_find_file_has_8dot3name(&fd)) {
9854: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9855: FindClose(dtainfo->find_handle);
9856: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9857: break;
9858: }
9859: }
9860: }
1.1.1.13 root 9861: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9862: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
9863: msdos_find_file_conv_local_time(&fd);
9864: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
9865: find->size = fd.nFileSizeLow;
1.1.1.13 root 9866: strcpy(find->name, msdos_short_name(&fd));
1.1 root 9867: REG16(AX) = 0;
1.1.1.14 root 9868: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9869: find->attrib = 8;
9870: find->size = 0;
9871: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 9872: dtainfo->allowable_mask &= ~8;
1.1 root 9873: REG16(AX) = 0;
9874: } else {
9875: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 9876: m_CF = 1;
1.1 root 9877: }
9878: }
9879:
9880: inline void msdos_int_21h_4fh()
9881: {
9882: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9883: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9884: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 9885: WIN32_FIND_DATA fd;
9886:
1.1.1.14 root 9887: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
9888: REG16(AX) = 0x12;
9889: m_CF = 1;
9890: return;
9891: }
9892: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 9893: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9894: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 9895: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9896: !msdos_find_file_has_8dot3name(&fd)) {
9897: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9898: FindClose(dtainfo->find_handle);
9899: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9900: break;
9901: }
9902: }
9903: } else {
1.1.1.13 root 9904: FindClose(dtainfo->find_handle);
9905: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9906: }
9907: }
1.1.1.13 root 9908: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9909: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
9910: msdos_find_file_conv_local_time(&fd);
9911: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
9912: find->size = fd.nFileSizeLow;
1.1.1.13 root 9913: strcpy(find->name, msdos_short_name(&fd));
1.1 root 9914: REG16(AX) = 0;
1.1.1.14 root 9915: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9916: find->attrib = 8;
9917: find->size = 0;
9918: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 9919: dtainfo->allowable_mask &= ~8;
1.1 root 9920: REG16(AX) = 0;
9921: } else {
9922: REG16(AX) = 0x12;
1.1.1.3 root 9923: m_CF = 1;
1.1 root 9924: }
9925: }
9926:
9927: inline void msdos_int_21h_50h()
9928: {
1.1.1.8 root 9929: if(current_psp != REG16(BX)) {
9930: process_t *process = msdos_process_info_get(current_psp);
9931: if(process != NULL) {
9932: process->psp = REG16(BX);
9933: }
9934: current_psp = REG16(BX);
1.1.1.23 root 9935: msdos_sda_update(current_psp);
1.1.1.8 root 9936: }
1.1 root 9937: }
9938:
9939: inline void msdos_int_21h_51h()
9940: {
9941: REG16(BX) = current_psp;
9942: }
9943:
9944: inline void msdos_int_21h_52h()
9945: {
1.1.1.25 root 9946: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 9947: i386_load_segment_descriptor(ES);
1.1.1.25 root 9948: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 9949: }
9950:
9951: inline void msdos_int_21h_54h()
9952: {
9953: process_t *process = msdos_process_info_get(current_psp);
9954:
9955: REG8(AL) = process->verify;
9956: }
9957:
9958: inline void msdos_int_21h_55h()
9959: {
9960: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
9961:
9962: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
9963: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
9964: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
9965: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
9966: psp->parent_psp = current_psp;
9967: }
9968:
9969: inline void msdos_int_21h_56h(int lfn)
9970: {
9971: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 9972: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
9973: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 9974:
9975: if(rename(src, dst)) {
9976: REG16(AX) = errno;
1.1.1.3 root 9977: m_CF = 1;
1.1 root 9978: }
9979: }
9980:
9981: inline void msdos_int_21h_57h()
9982: {
9983: FILETIME time, local;
1.1.1.14 root 9984: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 9985: HANDLE hHandle;
1.1 root 9986:
1.1.1.21 root 9987: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 9988: REG16(AX) = (UINT16)GetLastError();
9989: m_CF = 1;
9990: return;
9991: }
9992: ctime = atime = mtime = NULL;
9993:
1.1 root 9994: switch(REG8(AL)) {
9995: case 0x00:
1.1.1.6 root 9996: case 0x01:
1.1.1.14 root 9997: mtime = &time;
1.1.1.6 root 9998: break;
9999: case 0x04:
10000: case 0x05:
1.1.1.14 root 10001: atime = &time;
1.1 root 10002: break;
1.1.1.6 root 10003: case 0x06:
10004: case 0x07:
1.1.1.14 root 10005: ctime = &time;
10006: break;
10007: default:
1.1.1.22 root 10008: 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 10009: REG16(AX) = 0x01;
10010: m_CF = 1;
10011: return;
10012: }
10013: if(REG8(AL) & 1) {
1.1 root 10014: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
10015: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 10016: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 10017: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10018: m_CF = 1;
1.1 root 10019: }
1.1.1.14 root 10020: } else {
1.1.1.21 root 10021: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 10022: // assume a device and use the current time
10023: GetSystemTimeAsFileTime(&time);
10024: }
10025: FileTimeToLocalFileTime(&time, &local);
10026: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 10027: }
10028: }
10029:
10030: inline void msdos_int_21h_58h()
10031: {
10032: switch(REG8(AL)) {
10033: case 0x00:
1.1.1.7 root 10034: REG16(AX) = malloc_strategy;
10035: break;
10036: case 0x01:
1.1.1.24 root 10037: // switch(REG16(BX)) {
10038: switch(REG8(BL)) {
1.1.1.7 root 10039: case 0x0000:
10040: case 0x0001:
10041: case 0x0002:
10042: case 0x0040:
10043: case 0x0041:
10044: case 0x0042:
10045: case 0x0080:
10046: case 0x0081:
10047: case 0x0082:
10048: malloc_strategy = REG16(BX);
1.1.1.23 root 10049: msdos_sda_update(current_psp);
1.1.1.7 root 10050: break;
10051: default:
1.1.1.22 root 10052: 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 10053: REG16(AX) = 0x01;
10054: m_CF = 1;
10055: break;
10056: }
10057: break;
10058: case 0x02:
1.1.1.19 root 10059: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 10060: break;
10061: case 0x03:
1.1.1.24 root 10062: // switch(REG16(BX)) {
10063: switch(REG8(BL)) {
1.1.1.7 root 10064: case 0x0000:
1.1.1.19 root 10065: msdos_mem_unlink_umb();
10066: break;
1.1.1.7 root 10067: case 0x0001:
1.1.1.19 root 10068: msdos_mem_link_umb();
1.1.1.7 root 10069: break;
10070: default:
1.1.1.22 root 10071: 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 10072: REG16(AX) = 0x01;
10073: m_CF = 1;
10074: break;
10075: }
1.1 root 10076: break;
10077: default:
1.1.1.22 root 10078: 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 10079: REG16(AX) = 0x01;
1.1.1.3 root 10080: m_CF = 1;
1.1 root 10081: break;
10082: }
10083: }
10084:
10085: inline void msdos_int_21h_59h()
10086: {
1.1.1.23 root 10087: sda_t *sda = (sda_t *)(mem + SDA_TOP);
10088:
10089: REG16(AX) = sda->extended_error_code;
10090: REG8(BH) = sda->error_class;
10091: REG8(BL) = sda->suggested_action;
10092: REG8(CH) = sda->locus_of_last_error;
1.1 root 10093: }
10094:
10095: inline void msdos_int_21h_5ah()
10096: {
1.1.1.3 root 10097: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10098: int len = strlen(path);
10099: char tmp[MAX_PATH];
10100:
10101: if(GetTempFileName(path, "TMP", 0, tmp)) {
10102: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10103:
10104: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10105: REG16(AX) = fd;
10106: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10107: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10108:
10109: strcpy(path, tmp);
10110: int dx = REG16(DX) + len;
1.1.1.3 root 10111: int ds = SREG(DS);
1.1 root 10112: while(dx > 0xffff) {
10113: dx -= 0x10;
10114: ds++;
10115: }
10116: REG16(DX) = dx;
1.1.1.3 root 10117: SREG(DS) = ds;
10118: i386_load_segment_descriptor(DS);
1.1 root 10119: } else {
10120: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10121: m_CF = 1;
1.1 root 10122: }
10123: }
10124:
10125: inline void msdos_int_21h_5bh()
10126: {
1.1.1.3 root 10127: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10128:
1.1.1.24 root 10129: if(msdos_is_existing_file(path)) {
1.1 root 10130: // already exists
10131: REG16(AX) = 0x50;
1.1.1.3 root 10132: m_CF = 1;
1.1 root 10133: } else {
10134: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10135:
10136: if(fd != -1) {
10137: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10138: REG16(AX) = fd;
10139: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10140: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10141: } else {
10142: REG16(AX) = errno;
1.1.1.3 root 10143: m_CF = 1;
1.1 root 10144: }
10145: }
10146: }
10147:
10148: inline void msdos_int_21h_5ch()
10149: {
10150: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10151: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10152:
1.1.1.20 root 10153: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 10154: if(REG8(AL) == 0 || REG8(AL) == 1) {
1.1.1.35 root 10155: static const int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 10156: UINT32 pos = _tell(fd);
10157: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
10158: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 10159: REG16(AX) = errno;
1.1.1.3 root 10160: m_CF = 1;
1.1 root 10161: }
1.1.1.20 root 10162: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 10163:
1.1 root 10164: // some seconds may be passed in _locking()
1.1.1.35 root 10165: REQUEST_HARDWRE_UPDATE();
1.1 root 10166: } else {
10167: REG16(AX) = 0x01;
1.1.1.3 root 10168: m_CF = 1;
1.1 root 10169: }
10170: } else {
10171: REG16(AX) = 0x06;
1.1.1.3 root 10172: m_CF = 1;
1.1 root 10173: }
10174: }
10175:
1.1.1.22 root 10176: inline void msdos_int_21h_5dh()
10177: {
10178: switch(REG8(AL)) {
10179: case 0x06: // get address of dos swappable data area
1.1.1.23 root 10180: SREG(DS) = (SDA_TOP >> 4);
10181: i386_load_segment_descriptor(DS);
10182: REG16(SI) = offsetof(sda_t, crit_error_flag);
10183: REG16(CX) = 0x80;
10184: REG16(DX) = 0x1a;
10185: break;
10186: case 0x0b: // get dos swappable data areas
1.1.1.22 root 10187: REG16(AX) = 0x01;
10188: m_CF = 1;
10189: break;
10190: case 0x08: // set redirected printer mode
10191: case 0x09: // flush redirected printer output
10192: case 0x0a: // set extended error information
10193: break;
10194: default:
10195: 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));
10196: REG16(AX) = 0x01;
10197: m_CF = 1;
10198: break;
10199: }
10200: }
10201:
1.1.1.30 root 10202: inline void msdos_int_21h_5fh()
10203: {
10204: switch(REG8(AL)) {
10205: case 0x02:
10206: {
10207: DWORD drives = GetLogicalDrives();
10208: for(int i = 0, index = 0; i < 26; i++) {
10209: if(drives & (1 << i)) {
10210: char volume[] = "A:\\";
10211: volume[0] = 'A' + i;
10212: if(GetDriveType(volume) == DRIVE_REMOTE) {
10213: if(index == REG16(BX)) {
10214: DWORD dwSize = 128;
10215: volume[2] = '\0';
10216: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
10217: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
10218: REG8(BH) = 0x00; // valid
10219: REG8(BL) = 0x04; // disk drive
10220: REG16(CX) = 0x00;
10221: return;
10222: }
10223: index++;
10224: }
10225: }
10226: }
10227: }
10228: REG16(AX) = 0x12; // no more files
10229: m_CF = 1;
10230: break;
10231: default:
10232: 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));
10233: REG16(AX) = 0x01;
10234: m_CF = 1;
10235: break;
10236: }
10237: }
10238:
1.1 root 10239: inline void msdos_int_21h_60h(int lfn)
10240: {
1.1.1.14 root 10241: char full[MAX_PATH], *path;
10242:
1.1 root 10243: if(lfn) {
1.1.1.14 root 10244: char *name;
10245: *full = '\0';
1.1.1.3 root 10246: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 10247: switch(REG8(CL)) {
10248: case 1:
10249: GetShortPathName(full, full, MAX_PATH);
10250: my_strupr(full);
10251: break;
10252: case 2:
10253: GetLongPathName(full, full, MAX_PATH);
10254: break;
10255: }
10256: path = full;
10257: } else {
10258: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
10259: }
10260: if(*path != '\0') {
10261: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 10262: } else {
1.1.1.14 root 10263: REG16(AX) = (UINT16)GetLastError();
10264: m_CF = 1;
1.1 root 10265: }
10266: }
10267:
10268: inline void msdos_int_21h_61h()
10269: {
10270: REG8(AL) = 0;
10271: }
10272:
10273: inline void msdos_int_21h_62h()
10274: {
10275: REG16(BX) = current_psp;
10276: }
10277:
10278: inline void msdos_int_21h_63h()
10279: {
10280: switch(REG8(AL)) {
10281: case 0x00:
1.1.1.3 root 10282: SREG(DS) = (DBCS_TABLE >> 4);
10283: i386_load_segment_descriptor(DS);
1.1 root 10284: REG16(SI) = (DBCS_TABLE & 0x0f);
10285: REG8(AL) = 0x00;
10286: break;
1.1.1.22 root 10287: case 0x01: // set korean input mode
10288: case 0x02: // get korean input mode
10289: REG8(AL) = 0xff; // not supported
10290: break;
1.1 root 10291: default:
1.1.1.22 root 10292: 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 10293: REG16(AX) = 0x01;
1.1.1.3 root 10294: m_CF = 1;
1.1 root 10295: break;
10296: }
10297: }
10298:
1.1.1.25 root 10299: UINT16 get_extended_country_info(UINT8 func)
1.1 root 10300: {
1.1.1.25 root 10301: switch(func) {
1.1.1.17 root 10302: case 0x01:
10303: if(REG16(CX) >= 5) {
1.1.1.19 root 10304: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 10305: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
10306: REG16(CX) = sizeof(data);
10307: ZeroMemory(data, sizeof(data));
10308: data[0] = 0x01;
10309: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 10310: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 10311: *(UINT16 *)(data + 5) = active_code_page;
10312: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 10313: // REG16(AX) = active_code_page;
1.1.1.17 root 10314: } else {
1.1.1.25 root 10315: return(0x08); // insufficient memory
1.1.1.17 root 10316: }
10317: break;
10318: case 0x02:
10319: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
10320: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
10321: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 10322: // REG16(AX) = active_code_page;
1.1.1.17 root 10323: REG16(CX) = 0x05;
10324: break;
1.1.1.23 root 10325: case 0x03:
10326: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
10327: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
10328: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 10329: // REG16(AX) = active_code_page;
1.1.1.23 root 10330: REG16(CX) = 0x05;
10331: break;
1.1.1.17 root 10332: case 0x04:
10333: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
10334: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
10335: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 10336: // REG16(AX) = active_code_page;
1.1.1.17 root 10337: REG16(CX) = 0x05;
10338: break;
10339: case 0x05:
10340: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
10341: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
10342: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 10343: // REG16(AX) = active_code_page;
1.1.1.17 root 10344: REG16(CX) = 0x05;
10345: break;
10346: case 0x06:
10347: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
10348: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
10349: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 10350: // REG16(AX) = active_code_page;
1.1.1.17 root 10351: REG16(CX) = 0x05;
10352: break;
1.1 root 10353: case 0x07:
1.1.1.3 root 10354: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
10355: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
10356: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 10357: // REG16(AX) = active_code_page;
1.1 root 10358: REG16(CX) = 0x05;
10359: break;
1.1.1.25 root 10360: default:
10361: return(0x01); // function number invalid
10362: }
10363: return(0x00);
10364: }
10365:
10366: inline void msdos_int_21h_65h()
10367: {
10368: char tmp[0x10000];
10369:
10370: switch(REG8(AL)) {
10371: case 0x01:
10372: case 0x02:
10373: case 0x03:
10374: case 0x04:
10375: case 0x05:
10376: case 0x06:
10377: case 0x07:
10378: {
10379: UINT16 result = get_extended_country_info(REG8(AL));
10380: if(result) {
10381: REG16(AX) = result;
10382: m_CF = 1;
10383: } else {
10384: REG16(AX) = active_code_page; // FIXME: is this correct???
10385: }
10386: }
10387: break;
1.1 root 10388: case 0x20:
1.1.1.25 root 10389: case 0xa0:
1.1.1.19 root 10390: memset(tmp, 0, sizeof(tmp));
10391: tmp[0] = REG8(DL);
1.1 root 10392: my_strupr(tmp);
10393: REG8(DL) = tmp[0];
10394: break;
10395: case 0x21:
1.1.1.25 root 10396: case 0xa1:
1.1 root 10397: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 10398: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10399: my_strupr(tmp);
1.1.1.3 root 10400: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 10401: break;
10402: case 0x22:
1.1.1.25 root 10403: case 0xa2:
1.1.1.3 root 10404: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 10405: break;
1.1.1.25 root 10406: case 0x23:
10407: // FIXME: need to check multi-byte (kanji) charactre?
10408: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
10409: // 8278h/8299h: multi-byte (kanji) Y and y
10410: REG16(AX) = 0x00;
10411: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
10412: // 826dh/828eh: multi-byte (kanji) N and n
10413: REG16(AX) = 0x01;
10414: } else {
10415: REG16(AX) = 0x02;
10416: }
10417: break;
1.1 root 10418: default:
1.1.1.22 root 10419: 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 10420: REG16(AX) = 0x01;
1.1.1.3 root 10421: m_CF = 1;
1.1 root 10422: break;
10423: }
10424: }
10425:
10426: inline void msdos_int_21h_66h()
10427: {
10428: switch(REG8(AL)) {
10429: case 0x01:
10430: REG16(BX) = active_code_page;
10431: REG16(DX) = system_code_page;
10432: break;
10433: case 0x02:
10434: if(active_code_page == REG16(BX)) {
10435: REG16(AX) = 0xeb41;
10436: } else if(_setmbcp(REG16(BX)) == 0) {
10437: active_code_page = REG16(BX);
1.1.1.17 root 10438: msdos_nls_tables_update();
1.1 root 10439: REG16(AX) = 0xeb41;
1.1.1.32 root 10440: SetConsoleCP(active_code_page);
10441: SetConsoleOutputCP(active_code_page);
1.1 root 10442: } else {
10443: REG16(AX) = 0x25;
1.1.1.3 root 10444: m_CF = 1;
1.1 root 10445: }
10446: break;
10447: default:
1.1.1.22 root 10448: 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 10449: REG16(AX) = 0x01;
1.1.1.3 root 10450: m_CF = 1;
1.1 root 10451: break;
10452: }
10453: }
10454:
10455: inline void msdos_int_21h_67h()
10456: {
10457: process_t *process = msdos_process_info_get(current_psp);
10458:
10459: if(REG16(BX) <= MAX_FILES) {
10460: process->max_files = max(REG16(BX), 20);
10461: } else {
10462: REG16(AX) = 0x08;
1.1.1.3 root 10463: m_CF = 1;
1.1 root 10464: }
10465: }
10466:
10467: inline void msdos_int_21h_68h()
10468: {
10469: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10470: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10471:
1.1.1.20 root 10472: if(fd < process->max_files && file_handler[fd].valid) {
10473: // fflush(_fdopen(fd, ""));
1.1 root 10474: } else {
10475: REG16(AX) = 0x06;
1.1.1.3 root 10476: m_CF = 1;
1.1 root 10477: }
10478: }
10479:
10480: inline void msdos_int_21h_69h()
10481: {
1.1.1.3 root 10482: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10483: char path[] = "A:\\";
10484: char volume_label[MAX_PATH];
10485: DWORD serial_number = 0;
10486: char file_system[MAX_PATH];
10487:
10488: if(REG8(BL) == 0) {
10489: path[0] = 'A' + _getdrive() - 1;
10490: } else {
10491: path[0] = 'A' + REG8(BL) - 1;
10492: }
10493:
10494: switch(REG8(AL)) {
10495: case 0x00:
10496: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
10497: info->info_level = 0;
10498: info->serial_number = serial_number;
10499: memset(info->volume_label, 0x20, 11);
10500: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
10501: memset(info->file_system, 0x20, 8);
10502: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
10503: } else {
10504: REG16(AX) = errno;
1.1.1.3 root 10505: m_CF = 1;
1.1 root 10506: }
10507: break;
10508: case 0x01:
10509: REG16(AX) = 0x03;
1.1.1.3 root 10510: m_CF = 1;
1.1 root 10511: }
10512: }
10513:
10514: inline void msdos_int_21h_6ah()
10515: {
10516: REG8(AH) = 0x68;
10517: msdos_int_21h_68h();
10518: }
10519:
10520: inline void msdos_int_21h_6bh()
10521: {
10522: REG8(AL) = 0;
10523: }
10524:
10525: inline void msdos_int_21h_6ch(int lfn)
10526: {
1.1.1.3 root 10527: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 10528: int mode = REG8(BL) & 0x03;
10529:
10530: if(mode < 0x03) {
1.1.1.29 root 10531: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 10532: // file exists
10533: if(REG8(DL) & 1) {
1.1.1.29 root 10534: int fd = -1, c;
1.1.1.11 root 10535: UINT16 info;
1.1 root 10536:
1.1.1.11 root 10537: if(msdos_is_con_path(path)) {
1.1.1.13 root 10538: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 10539: info = 0x80d3;
1.1.1.29 root 10540: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
10541: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
10542: fd = msdos_open("NUL", file_mode[mode].mode);
10543: }
1.1.1.14 root 10544: info = 0x80d3;
1.1.1.29 root 10545: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10546: fd = msdos_open("NUL", file_mode[mode].mode);
10547: info = 0x80d3;
1.1.1.11 root 10548: } else {
1.1.1.13 root 10549: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 10550: info = msdos_drive_number(path);
10551: }
1.1 root 10552: if(fd != -1) {
10553: REG16(AX) = fd;
10554: REG16(CX) = 1;
1.1.1.11 root 10555: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 10556: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10557: } else {
10558: REG16(AX) = errno;
1.1.1.3 root 10559: m_CF = 1;
1.1 root 10560: }
10561: } else if(REG8(DL) & 2) {
10562: int attr = GetFileAttributes(path);
1.1.1.29 root 10563: int fd = -1, c;
1.1.1.11 root 10564: UINT16 info;
1.1 root 10565:
1.1.1.11 root 10566: if(msdos_is_con_path(path)) {
1.1.1.13 root 10567: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 10568: info = 0x80d3;
1.1.1.29 root 10569: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
10570: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
10571: fd = msdos_open("NUL", file_mode[mode].mode);
10572: }
1.1.1.14 root 10573: info = 0x80d3;
1.1.1.29 root 10574: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10575: fd = msdos_open("NUL", file_mode[mode].mode);
10576: info = 0x80d3;
1.1 root 10577: } else {
10578: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 10579: info = msdos_drive_number(path);
1.1 root 10580: }
10581: if(fd != -1) {
10582: if(attr == -1) {
10583: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
10584: }
10585: SetFileAttributes(path, attr);
10586: REG16(AX) = fd;
10587: REG16(CX) = 3;
1.1.1.11 root 10588: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 10589: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10590: } else {
10591: REG16(AX) = errno;
1.1.1.3 root 10592: m_CF = 1;
1.1 root 10593: }
10594: } else {
10595: REG16(AX) = 0x50;
1.1.1.3 root 10596: m_CF = 1;
1.1 root 10597: }
10598: } else {
10599: // file not exists
10600: if(REG8(DL) & 0x10) {
10601: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10602:
10603: if(fd != -1) {
10604: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10605: REG16(AX) = fd;
10606: REG16(CX) = 2;
10607: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10608: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10609: } else {
10610: REG16(AX) = errno;
1.1.1.3 root 10611: m_CF = 1;
1.1 root 10612: }
10613: } else {
10614: REG16(AX) = 0x02;
1.1.1.3 root 10615: m_CF = 1;
1.1 root 10616: }
10617: }
10618: } else {
10619: REG16(AX) = 0x0c;
1.1.1.3 root 10620: m_CF = 1;
1.1 root 10621: }
10622: }
10623:
10624: inline void msdos_int_21h_710dh()
10625: {
10626: // reset drive
10627: }
10628:
1.1.1.17 root 10629: inline void msdos_int_21h_7141h(int lfn)
10630: {
10631: if(REG16(SI) == 0) {
10632: msdos_int_21h_41h(lfn);
10633: return;
10634: }
10635: if(REG16(SI) != 1) {
10636: REG16(AX) = 5;
10637: m_CF = 1;
10638: }
10639: /* wild card and matching attributes... */
10640: char tmp[MAX_PATH * 2];
10641: // copy search pathname (and quick check overrun)
10642: ZeroMemory(tmp, sizeof(tmp));
10643: tmp[MAX_PATH - 1] = '\0';
10644: tmp[MAX_PATH] = 1;
10645: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
10646:
10647: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
10648: REG16(AX) = 1;
10649: m_CF = 1;
10650: return;
10651: }
10652: for(char *s = tmp; *s; ++s) {
10653: if(*s == '/') {
10654: *s = '\\';
10655: }
10656: }
10657: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
10658: if(tmp_name) {
10659: ++tmp_name;
10660: } else {
10661: tmp_name = strchr(tmp, ':');
10662: tmp_name = tmp_name ? tmp_name + 1 : tmp;
10663: }
10664:
10665: WIN32_FIND_DATAA fd;
10666: HANDLE fh = FindFirstFileA(tmp, &fd);
10667: if(fh == INVALID_HANDLE_VALUE) {
10668: REG16(AX) = 2;
10669: m_CF = 1;
10670: return;
10671: }
10672: do {
10673: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
10674: strcpy(tmp_name, fd.cFileName);
10675: if(remove(msdos_trimmed_path(tmp, lfn))) {
10676: REG16(AX) = 5;
10677: m_CF = 1;
10678: break;
10679: }
10680: }
10681: } while(FindNextFileA(fh, &fd));
10682: if(!m_CF) {
10683: if(GetLastError() != ERROR_NO_MORE_FILES) {
10684: m_CF = 1;
10685: REG16(AX) = 2;
10686: }
10687: }
10688: FindClose(fh);
10689: }
10690:
1.1 root 10691: inline void msdos_int_21h_714eh()
10692: {
10693: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 10694: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
10695: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10696: WIN32_FIND_DATA fd;
10697:
1.1.1.13 root 10698: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
10699: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10700: FindClose(dtainfo->find_handle);
10701: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10702: }
10703: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 10704: dtainfo->allowable_mask = REG8(CL);
10705: dtainfo->required_mask = REG8(CH);
10706: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 10707:
1.1.1.14 root 10708: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
10709: dtainfo->allowable_mask &= ~8;
1.1 root 10710: }
1.1.1.14 root 10711: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
10712: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 10713: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10714: FindClose(dtainfo->find_handle);
10715: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10716: break;
10717: }
10718: }
10719: }
1.1.1.13 root 10720: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10721: find->attrib = fd.dwFileAttributes;
10722: msdos_find_file_conv_local_time(&fd);
10723: if(REG16(SI) == 0) {
10724: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
10725: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
10726: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
10727: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
10728: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
10729: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
10730: } else {
10731: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
10732: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
10733: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
10734: }
10735: find->size_hi = fd.nFileSizeHigh;
10736: find->size_lo = fd.nFileSizeLow;
10737: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 10738: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 10739: REG16(AX) = dtainfo - dtalist + 1;
10740: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10741: // volume label
10742: find->attrib = 8;
10743: find->size_hi = find->size_lo = 0;
10744: strcpy(find->full_name, process->volume_label);
10745: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10746: dtainfo->allowable_mask &= ~8;
10747: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 10748: } else {
10749: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 10750: m_CF = 1;
1.1 root 10751: }
10752: }
10753:
10754: inline void msdos_int_21h_714fh()
10755: {
10756: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 10757: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 10758: WIN32_FIND_DATA fd;
10759:
1.1.1.14 root 10760: if(REG16(BX) - 1u >= MAX_DTAINFO) {
10761: REG16(AX) = 6;
1.1.1.13 root 10762: m_CF = 1;
10763: return;
10764: }
1.1.1.14 root 10765: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 10766: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10767: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 10768: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 10769: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10770: FindClose(dtainfo->find_handle);
10771: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10772: break;
10773: }
10774: }
10775: } else {
1.1.1.13 root 10776: FindClose(dtainfo->find_handle);
10777: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10778: }
10779: }
1.1.1.13 root 10780: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10781: find->attrib = fd.dwFileAttributes;
10782: msdos_find_file_conv_local_time(&fd);
10783: if(REG16(SI) == 0) {
10784: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
10785: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
10786: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
10787: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
10788: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
10789: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
10790: } else {
10791: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
10792: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
10793: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
10794: }
10795: find->size_hi = fd.nFileSizeHigh;
10796: find->size_lo = fd.nFileSizeLow;
10797: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 10798: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 10799: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10800: // volume label
10801: find->attrib = 8;
10802: find->size_hi = find->size_lo = 0;
10803: strcpy(find->full_name, process->volume_label);
10804: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10805: dtainfo->allowable_mask &= ~8;
1.1 root 10806: } else {
10807: REG16(AX) = 0x12;
1.1.1.3 root 10808: m_CF = 1;
1.1 root 10809: }
10810: }
10811:
10812: inline void msdos_int_21h_71a0h()
10813: {
10814: DWORD max_component_len, file_sys_flag;
10815:
1.1.1.14 root 10816: 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))) {
10817: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
10818: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 10819: REG16(CX) = (UINT16)max_component_len; // 255
10820: REG16(DX) = (UINT16)max_component_len + 5; // 260
10821: } else {
10822: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10823: m_CF = 1;
1.1 root 10824: }
10825: }
10826:
10827: inline void msdos_int_21h_71a1h()
10828: {
1.1.1.14 root 10829: if(REG16(BX) - 1u >= MAX_DTAINFO) {
10830: REG16(AX) = 6;
1.1.1.13 root 10831: m_CF = 1;
10832: return;
10833: }
1.1.1.14 root 10834: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 10835: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10836: FindClose(dtainfo->find_handle);
10837: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10838: }
10839: }
10840:
10841: inline void msdos_int_21h_71a6h()
10842: {
10843: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10844: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
10845:
1.1.1.3 root 10846: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10847: struct _stat64 status;
10848: DWORD serial_number = 0;
10849:
1.1.1.20 root 10850: if(fd < process->max_files && file_handler[fd].valid) {
10851: if(_fstat64(fd, &status) == 0) {
10852: if(file_handler[fd].path[1] == ':') {
1.1 root 10853: // NOTE: we need to consider the network file path "\\host\share\"
10854: char volume[] = "A:\\";
1.1.1.20 root 10855: volume[0] = file_handler[fd].path[1];
1.1 root 10856: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
10857: }
1.1.1.20 root 10858: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 10859: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
10860: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
10861: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
10862: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
10863: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
10864: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
10865: *(UINT32 *)(buffer + 0x1c) = serial_number;
10866: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
10867: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
10868: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 10869: // this is dummy id and it will be changed when it is reopened...
1.1 root 10870: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 10871: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 10872: } else {
10873: REG16(AX) = errno;
1.1.1.3 root 10874: m_CF = 1;
1.1 root 10875: }
10876: } else {
10877: REG16(AX) = 0x06;
1.1.1.3 root 10878: m_CF = 1;
1.1 root 10879: }
10880: }
10881:
10882: inline void msdos_int_21h_71a7h()
10883: {
10884: switch(REG8(BL)) {
10885: case 0x00:
1.1.1.3 root 10886: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 10887: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10888: m_CF = 1;
1.1 root 10889: }
10890: break;
10891: case 0x01:
10892: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 10893: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 10894: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10895: m_CF = 1;
1.1 root 10896: }
10897: break;
10898: default:
1.1.1.22 root 10899: 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 10900: REG16(AX) = 0x01;
1.1.1.3 root 10901: m_CF = 1;
1.1 root 10902: break;
10903: }
10904: }
10905:
10906: inline void msdos_int_21h_71a8h()
10907: {
10908: if(REG8(DH) == 0) {
10909: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 10910: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 10911: memset(fcb, 0x20, sizeof(fcb));
10912: int len = strlen(tmp);
1.1.1.21 root 10913: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 10914: if(tmp[i] == '.') {
10915: pos = 8;
10916: } else {
10917: if(msdos_lead_byte_check(tmp[i])) {
10918: fcb[pos++] = tmp[i++];
10919: }
10920: fcb[pos++] = tmp[i];
10921: }
10922: }
1.1.1.3 root 10923: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 10924: } else {
1.1.1.3 root 10925: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 10926: }
10927: }
10928:
1.1.1.22 root 10929: inline void msdos_int_21h_71aah()
10930: {
10931: char drv[] = "A:", path[MAX_PATH];
10932: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
10933:
10934: if(REG8(BL) == 0) {
10935: drv[0] = 'A' + _getdrive() - 1;
10936: } else {
10937: drv[0] = 'A' + REG8(BL) - 1;
10938: }
10939: switch(REG8(BH)) {
10940: case 0x00:
10941: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
10942: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10943: if(GetLogicalDrives() & bits) {
10944: REG16(AX) = 0x0f; // invalid drive
10945: } else {
10946: REG16(AX) = 0x03; // path not found
10947: }
10948: m_CF = 1;
10949: }
10950: break;
10951: case 0x01:
10952: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
10953: REG16(AX) = 0x0f; // invalid drive
10954: m_CF = 1;
10955: }
10956: break;
10957: case 0x02:
10958: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
10959: REG16(AX) = 0x0f; // invalid drive
10960: m_CF = 1;
10961: } else if(strncmp(path, "\\??\\", 4) != 0) {
10962: REG16(AX) = 0x0f; // invalid drive
10963: m_CF = 1;
10964: } else {
10965: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
10966: }
10967: break;
10968: default:
10969: 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));
10970: REG16(AX) = 0x01;
10971: m_CF = 1;
10972: break;
10973: }
10974: }
10975:
1.1.1.14 root 10976: inline void msdos_int_21h_7300h()
10977: {
10978: if(REG8(AL) == 0) {
10979: REG8(AL) = REG8(CL);
10980: REG8(AH) = 0;
10981: } else {
10982: REG16(AX) = 0x01;
10983: m_CF = 1;
10984: }
10985: }
10986:
10987: inline void msdos_int_21h_7302h()
10988: {
10989: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
10990: UINT16 seg, ofs;
10991:
10992: if(REG16(CX) < 0x3f) {
10993: REG8(AL) = 0x18;
10994: m_CF = 1;
10995: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
10996: REG8(AL) = 0xff;
10997: m_CF = 1;
10998: } else {
10999: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
11000: }
11001: }
11002:
1.1 root 11003: inline void msdos_int_21h_7303h()
11004: {
1.1.1.3 root 11005: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
11006: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 11007: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
11008:
11009: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
11010: info->size_of_structure = sizeof(ext_space_info_t);
11011: info->structure_version = 0;
11012: info->sectors_per_cluster = sectors_per_cluster;
11013: info->bytes_per_sector = bytes_per_sector;
11014: info->available_clusters_on_drive = free_clusters;
11015: info->total_clusters_on_drive = total_clusters;
11016: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
11017: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
11018: info->available_allocation_units = free_clusters; // ???
11019: info->total_allocation_units = total_clusters; // ???
11020: } else {
11021: REG16(AX) = errno;
1.1.1.3 root 11022: m_CF = 1;
1.1 root 11023: }
11024: }
11025:
1.1.1.30 root 11026: inline void msdos_int_21h_dbh()
11027: {
11028: // Novell NetWare - Workstation - Get Number of Local Drives
11029: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
11030: REG8(AL) = dos_info->last_drive;
11031: }
11032:
11033: inline void msdos_int_21h_dch()
11034: {
11035: // Novell NetWare - Connection Services - Get Connection Number
11036: REG8(AL) = 0x00;
11037: }
11038:
1.1.1.32 root 11039: inline void msdos_int_24h()
11040: {
11041: const char *message = NULL;
11042: int key = 0;
11043:
11044: for(int i = 0; i < array_length(critical_error_table); i++) {
11045: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
11046: if(active_code_page == 932) {
11047: message = critical_error_table[i].message_japanese;
11048: }
11049: if(message == NULL) {
11050: message = critical_error_table[i].message_english;
11051: }
11052: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
11053: strcpy((char *)(mem + WORK_TOP + 1), message);
11054:
11055: SREG(ES) = WORK_TOP >> 4;
11056: i386_load_segment_descriptor(ES);
11057: REG16(DI) = 0x0000;
11058: break;
11059: }
11060: }
11061: fprintf(stderr, "\n%s", message);
11062: if(!(REG8(AH) & 0x80)) {
11063: if(REG8(AH) & 0x01) {
11064: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
11065: } else {
11066: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
11067: }
11068: }
11069: fprintf(stderr, "\n");
11070:
1.1.1.33 root 11071: {
1.1.1.32 root 11072: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
1.1.1.33 root 11073: }
1.1.1.32 root 11074: if(REG8(AH) & 0x10) {
11075: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
11076: }
11077: if(REG8(AH) & 0x20) {
11078: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
11079: }
11080: if(REG8(AH) & 0x08) {
11081: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
11082: }
11083: fprintf(stderr, "? ");
11084:
11085: while(1) {
11086: while(!_kbhit()) {
11087: Sleep(10);
11088: }
11089: key = _getch();
11090:
11091: if(key == 'I' || key == 'i') {
11092: if(REG8(AH) & 0x20) {
11093: REG8(AL) = 0;
11094: break;
11095: }
11096: } else if(key == 'R' || key == 'r') {
11097: if(REG8(AH) & 0x10) {
11098: REG8(AL) = 1;
11099: break;
11100: }
11101: } else if(key == 'A' || key == 'a') {
11102: REG8(AL) = 2;
11103: break;
11104: } else if(key == 'F' || key == 'f') {
11105: if(REG8(AH) & 0x08) {
11106: REG8(AL) = 3;
11107: break;
11108: }
11109: }
11110: }
11111: fprintf(stderr, "%c\n", key);
11112: }
11113:
1.1 root 11114: inline void msdos_int_25h()
11115: {
11116: UINT16 seg, ofs;
11117: DWORD dwSize;
11118:
1.1.1.3 root 11119: #if defined(HAS_I386)
11120: I386OP(pushf)();
11121: #else
11122: PREFIX86(_pushf());
11123: #endif
1.1 root 11124:
11125: if(!(REG8(AL) < 26)) {
11126: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 11127: m_CF = 1;
1.1 root 11128: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
11129: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11130: m_CF = 1;
1.1 root 11131: } else {
11132: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
11133: char dev[64];
11134: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
11135:
11136: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
11137: if(hFile == INVALID_HANDLE_VALUE) {
11138: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11139: m_CF = 1;
1.1 root 11140: } else {
1.1.1.19 root 11141: UINT32 top_sector = REG16(DX);
11142: UINT16 sector_num = REG16(CX);
11143: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
11144:
11145: if(sector_num == 0xffff) {
11146: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
11147: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
11148: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
11149: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
11150: buffer_addr = (seg << 4) + ofs;
11151: }
11152: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
11153: // REG8(AL) = 0x02; // drive not ready
11154: // m_CF = 1;
11155: // } else
11156: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 11157: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 11158: m_CF = 1;
1.1.1.19 root 11159: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 11160: REG8(AL) = 0x0b; // read error
1.1.1.3 root 11161: m_CF = 1;
1.1 root 11162: }
11163: CloseHandle(hFile);
11164: }
11165: }
11166: }
11167:
11168: inline void msdos_int_26h()
11169: {
11170: // this operation may cause serious damage for drives, so always returns error...
11171: UINT16 seg, ofs;
11172: DWORD dwSize;
11173:
1.1.1.3 root 11174: #if defined(HAS_I386)
11175: I386OP(pushf)();
11176: #else
11177: PREFIX86(_pushf());
11178: #endif
1.1 root 11179:
11180: if(!(REG8(AL) < 26)) {
11181: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 11182: m_CF = 1;
1.1 root 11183: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
11184: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11185: m_CF = 1;
1.1 root 11186: } else {
11187: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
11188: char dev[64];
11189: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
11190:
11191: if(dpb->media_type == 0xf8) {
11192: // this drive is not a floppy
1.1.1.6 root 11193: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
11194: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
11195: // }
1.1 root 11196: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11197: m_CF = 1;
1.1 root 11198: } else {
11199: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
11200: if(hFile == INVALID_HANDLE_VALUE) {
11201: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11202: m_CF = 1;
1.1 root 11203: } else {
1.1.1.19 root 11204: UINT32 top_sector = REG16(DX);
11205: UINT16 sector_num = REG16(CX);
11206: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
11207:
11208: if(sector_num == 0xffff) {
11209: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
11210: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
11211: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
11212: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
11213: buffer_addr = (seg << 4) + ofs;
11214: }
1.1 root 11215: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
11216: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11217: m_CF = 1;
1.1.1.19 root 11218: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 11219: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 11220: m_CF = 1;
1.1.1.19 root 11221: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 11222: REG8(AL) = 0x0a; // write error
1.1.1.3 root 11223: m_CF = 1;
1.1 root 11224: }
11225: CloseHandle(hFile);
11226: }
11227: }
11228: }
11229: }
11230:
11231: inline void msdos_int_27h()
11232: {
1.1.1.29 root 11233: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
11234: try {
11235: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
11236: } catch(...) {
11237: // recover the broken mcb
11238: int mcb_seg = SREG(CS) - 1;
11239: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 11240:
1.1.1.29 root 11241: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 11242: mcb->mz = 'M';
11243: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
11244:
1.1.1.29 root 11245: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.33 root 11246: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4));
1.1.1.29 root 11247: } else {
1.1.1.33 root 11248: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0);
1.1.1.29 root 11249: }
11250: } else {
11251: mcb->mz = 'Z';
1.1.1.30 root 11252: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 11253: }
11254: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
11255: }
1.1.1.3 root 11256: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 11257: }
11258:
11259: inline void msdos_int_29h()
11260: {
1.1.1.14 root 11261: #if 1
11262: // need to check escape sequences
1.1 root 11263: msdos_putch(REG8(AL));
1.1.1.14 root 11264: #else
11265: DWORD num;
11266: vram_flush();
1.1.1.23 root 11267: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 11268: cursor_moved = true;
11269: #endif
1.1 root 11270: }
11271:
11272: inline void msdos_int_2eh()
11273: {
11274: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
11275: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 11276: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 11277: char *token = my_strtok(tmp, " ");
11278: strcpy(command, token);
11279: strcpy(opt, token + strlen(token) + 1);
11280:
11281: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
11282: param->env_seg = 0;
11283: param->cmd_line.w.l = 44;
11284: param->cmd_line.w.h = (WORK_TOP >> 4);
11285: param->fcb1.w.l = 24;
11286: param->fcb1.w.h = (WORK_TOP >> 4);
11287: param->fcb2.w.l = 24;
11288: param->fcb2.w.h = (WORK_TOP >> 4);
11289:
11290: memset(mem + WORK_TOP + 24, 0x20, 20);
11291:
11292: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
11293: cmd_line->len = strlen(opt);
11294: strcpy(cmd_line->cmd, opt);
11295: cmd_line->cmd[cmd_line->len] = 0x0d;
11296:
1.1.1.28 root 11297: try {
11298: if(msdos_process_exec(command, param, 0)) {
11299: REG16(AX) = 0xffff; // error before processing command
11300: } else {
11301: // set flag to set retval to ax when the started process is terminated
11302: process_t *process = msdos_process_info_get(current_psp);
11303: process->called_by_int2eh = true;
11304: }
11305: } catch(...) {
11306: REG16(AX) = 0xffff; // error before processing command
11307: }
1.1 root 11308: }
11309:
1.1.1.29 root 11310: inline void msdos_int_2fh_05h()
11311: {
11312: switch(REG8(AL)) {
11313: case 0x00:
1.1.1.32 root 11314: REG8(AL) = 0xff;
11315: break;
11316: case 0x01:
11317: case 0x02:
11318: for(int i = 0; i < array_length(standard_error_table); i++) {
11319: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
11320: const char *message = NULL;
11321: if(active_code_page == 932) {
11322: message = standard_error_table[i].message_japanese;
11323: }
11324: if(message == NULL) {
11325: message = standard_error_table[i].message_english;
11326: }
11327: strcpy((char *)(mem + WORK_TOP), message);
11328:
11329: SREG(ES) = WORK_TOP >> 4;
11330: i386_load_segment_descriptor(ES);
11331: REG16(DI) = 0x0000;
11332: REG8(AL) = 0x01;
11333: break;
11334: }
11335: }
1.1.1.29 root 11336: break;
11337: default:
11338: 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));
11339: m_CF = 1;
11340: }
11341: }
11342:
1.1.1.22 root 11343: inline void msdos_int_2fh_11h()
11344: {
11345: switch(REG8(AL)) {
11346: case 0x00:
1.1.1.29 root 11347: if(i386_read_stack() == 0xdada) {
11348: // MSCDEX is not installed
11349: // REG8(AL) = 0x00;
11350: } else {
11351: // Network Redirector is not installed
11352: // REG8(AL) = 0x00;
11353: }
1.1.1.22 root 11354: break;
11355: default:
11356: 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 11357: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 11358: m_CF = 1;
11359: break;
11360: }
11361: }
11362:
1.1.1.21 root 11363: inline void msdos_int_2fh_12h()
11364: {
11365: switch(REG8(AL)) {
1.1.1.22 root 11366: case 0x00:
1.1.1.29 root 11367: // DOS 3.0+ internal functions are installed
1.1.1.22 root 11368: REG8(AL) = 0xff;
11369: break;
1.1.1.29 root 11370: // case 0x01: // DOS 3.0+ internal - Close Current File
11371: case 0x02:
11372: {
11373: UINT16 stack = i386_read_stack();
11374: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
11375: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
11376: i386_load_segment_descriptor(ES);
11377: }
11378: break;
1.1.1.30 root 11379: case 0x03:
11380: SREG(DS) = (DEVICE_TOP >> 4);
11381: i386_load_segment_descriptor(DS);
11382: break;
1.1.1.29 root 11383: case 0x04:
11384: {
11385: UINT16 stack = i386_read_stack();
11386: REG8(AL) = (stack == '/') ? '\\' : stack;
11387: #if defined(HAS_I386)
11388: m_ZF = (REG8(AL) == '\\');
11389: #else
11390: m_ZeroVal = (REG8(AL) != '\\');
11391: #endif
11392: }
11393: break;
11394: case 0x05:
11395: msdos_putch(i386_read_stack());
11396: break;
11397: // case 0x06: // DOS 3.0+ internal - Invole Critical Error
11398: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
11399: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
11400: // case 0x09: // DOS 3.0+ internal - Flush and FREE Disk Buffer
11401: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
11402: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
11403: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
11404: case 0x0d:
11405: {
11406: SYSTEMTIME time;
11407: FILETIME file_time;
11408: WORD dos_date, dos_time;
11409: GetLocalTime(&time);
11410: SystemTimeToFileTime(&time, &file_time);
11411: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
11412: REG16(AX) = dos_date;
11413: REG16(DX) = dos_time;
11414: }
11415: break;
11416: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
11417: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
11418: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
11419: case 0x11:
11420: {
11421: char path[MAX_PATH], *p;
11422: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
11423: my_strupr(path);
11424: while((p = my_strchr(path, '/')) != NULL) {
11425: *p = '\\';
11426: }
11427: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
11428: }
11429: break;
11430: case 0x12:
11431: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
11432: break;
11433: case 0x13:
11434: {
11435: char tmp[2] = {0};
11436: tmp[0] = i386_read_stack();
11437: my_strupr(tmp);
11438: REG8(AL) = tmp[0];
11439: }
11440: break;
11441: case 0x14:
11442: #if defined(HAS_I386)
11443: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
11444: #else
11445: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
11446: #endif
11447: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
11448: break;
11449: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 11450: case 0x16:
11451: if(REG16(BX) < 20) {
11452: SREG(ES) = SFT_TOP >> 4;
11453: i386_load_segment_descriptor(ES);
11454: REG16(DI) = 6 + 0x3b * REG16(BX);
11455:
11456: // update system file table
11457: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
11458: if(file_handler[REG16(BX)].valid) {
11459: int count = 0;
11460: for(int i = 0; i < 20; i++) {
11461: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
11462: count++;
11463: }
11464: }
11465: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
11466: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
11467: _lseek(REG16(BX), 0, SEEK_END);
11468: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
11469: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
11470: } else {
11471: memset(sft, 0, 0x3b);
11472: }
11473: } else {
11474: REG16(AX) = 0x06;
11475: m_CF = 1;
11476: }
11477: break;
1.1.1.29 root 11478: // case 0x17: // DOS 3.0+ internal - Get Current Directory Structure for Drive
11479: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
11480: // case 0x19: // DOS 3.0+ internal - Set Drive???
11481: case 0x1a:
11482: {
11483: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
11484: if(path[1] == ':') {
11485: if(path[0] >= 'a' && path[0] <= 'z') {
11486: REG8(AL) = path[0] - 'a' + 1;
11487: } else if(path[0] >= 'A' && path[0] <= 'Z') {
11488: REG8(AL) = path[0] - 'A' + 1;
11489: } else {
11490: REG8(AL) = 0xff; // invalid
11491: }
11492: strcpy(full, path);
11493: strcpy(path, full + 2);
11494: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
11495: if(full[0] >= 'a' && full[0] <= 'z') {
11496: REG8(AL) = full[0] - 'a' + 1;
11497: } else if(full[0] >= 'A' && full[0] <= 'Z') {
11498: REG8(AL) = full[0] - 'A' + 1;
11499: } else {
11500: REG8(AL) = 0xff; // invalid
11501: }
11502: } else {
11503: REG8(AL) = 0x00; // default
11504: }
11505: }
11506: break;
11507: case 0x1b:
11508: {
11509: int year = REG16(CX) + 1980;
11510: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
11511: }
11512: break;
11513: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
11514: // case 0x1d: // DOS 3.0+ internal - Sum Memory
11515: case 0x1e:
11516: {
11517: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
11518: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
11519: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
11520: #if defined(HAS_I386)
11521: m_ZF = (strcmp(full_1st, full_2nd) == 0);
11522: #else
11523: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
11524: #endif
11525: } else {
11526: #if defined(HAS_I386)
11527: m_ZF = (strcmp(path_1st, path_2nd) == 0);
11528: #else
11529: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
11530: #endif
11531: }
11532: }
11533: break;
11534: // case 0x1f: // DOS 3.0+ internal - Build Current Directory Structure
1.1.1.21 root 11535: case 0x20:
11536: {
11537: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11538:
11539: if(fd < 20) {
11540: SREG(ES) = current_psp;
11541: i386_load_segment_descriptor(ES);
11542: REG16(DI) = offsetof(psp_t, file_table) + fd;
11543: } else {
11544: REG16(AX) = 0x06;
11545: m_CF = 1;
11546: }
11547: }
11548: break;
1.1.1.29 root 11549: case 0x21:
11550: msdos_int_21h_60h(0);
11551: break;
11552: // case 0x22: // DOS 3.0+ internal - Set Extended Error Info
11553: // case 0x23: // DOS 3.0+ internal - Check If Character Device
11554: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
11555: case 0x25:
11556: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
11557: break;
11558: case 0x26:
11559: REG8(AL) = REG8(CL);
11560: msdos_int_21h_3dh();
11561: break;
11562: case 0x27:
11563: msdos_int_21h_3eh();
11564: break;
11565: case 0x28:
11566: REG16(AX) = REG16(BP);
11567: msdos_int_21h_42h();
11568: break;
11569: case 0x29:
11570: msdos_int_21h_3fh();
11571: break;
11572: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
11573: case 0x2b:
11574: REG16(AX) = REG16(BP);
11575: msdos_int_21h_44h();
11576: break;
11577: case 0x2c:
11578: REG16(BX) = DEVICE_TOP >> 4;
11579: REG16(AX) = 22;
11580: break;
11581: case 0x2d:
11582: {
11583: sda_t *sda = (sda_t *)(mem + SDA_TOP);
11584: REG16(AX) = sda->extended_error_code;
11585: }
11586: break;
11587: case 0x2e:
11588: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32 root 11589: SREG(ES) = 0x0001;
11590: i386_load_segment_descriptor(ES);
11591: REG16(DI) = 0x00;
11592: } else if(REG8(DL) == 0x08) {
11593: // dummy parameter error message read routine is at fffd:0010
11594: SREG(ES) = 0xfffd;
1.1.1.22 root 11595: i386_load_segment_descriptor(ES);
1.1.1.32 root 11596: REG16(DI) = 0x0010;
1.1.1.22 root 11597: }
11598: break;
1.1.1.29 root 11599: case 0x2f:
11600: if(REG16(DX) != 0) {
1.1.1.30 root 11601: dos_major_version = REG8(DL);
11602: dos_minor_version = REG8(DH);
1.1.1.29 root 11603: } else {
11604: REG8(DL) = 7;
11605: REG8(DH) = 10;
11606: }
11607: break;
11608: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
11609: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 11610: default:
11611: 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));
11612: REG16(AX) = 0x01;
11613: m_CF = 1;
11614: break;
11615: }
11616: }
11617:
1.1.1.30 root 11618: inline void msdos_int_2fh_13h()
11619: {
11620: static UINT16 prevDS = 0, prevDX = 0;
11621: static UINT16 prevES = 0, prevBX = 0;
11622: UINT16 tmp;
11623:
11624: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
11625: i386_load_segment_descriptor(DS);
11626: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
11627:
11628: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
11629: i386_load_segment_descriptor(ES);
11630: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
11631: }
11632:
1.1.1.22 root 11633: inline void msdos_int_2fh_14h()
11634: {
11635: switch(REG8(AL)) {
11636: case 0x00:
1.1.1.29 root 11637: // NLSFUNC.COM is installed
11638: REG8(AL) = 0xff;
1.1.1.25 root 11639: break;
11640: case 0x01:
11641: case 0x03:
11642: REG8(AL) = 0x00;
11643: active_code_page = REG16(BX);
11644: msdos_nls_tables_update();
11645: break;
11646: case 0x02:
11647: REG8(AL) = get_extended_country_info(REG16(BP));
11648: break;
11649: case 0x04:
11650: REG8(AL) = 0x00;
11651: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 11652: break;
11653: default:
11654: 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));
11655: REG16(AX) = 0x01;
11656: m_CF = 1;
11657: break;
11658: }
11659: }
11660:
11661: inline void msdos_int_2fh_15h()
11662: {
11663: switch(REG8(AL)) {
1.1.1.29 root 11664: case 0x00: // CD-ROM - Installation Check
11665: if(REG16(BX) == 0x0000) {
11666: // MSCDEX is not installed
11667: // REG8(AL) = 0x00;
11668: } else {
11669: // GRAPHICS.COM is not installed
11670: // REG8(AL) = 0x00;
11671: }
1.1.1.22 root 11672: break;
11673: case 0xff:
1.1.1.29 root 11674: if(REG16(BX) == 0x0000) {
11675: // CORELCDX is not installed
11676: } else {
11677: 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));
11678: REG16(AX) = 0x01;
11679: m_CF = 1;
11680: }
1.1.1.22 root 11681: break;
1.1.1.21 root 11682: default:
1.1.1.22 root 11683: 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 11684: REG16(AX) = 0x01;
11685: m_CF = 1;
11686: break;
11687: }
11688: }
11689:
1.1 root 11690: inline void msdos_int_2fh_16h()
11691: {
11692: switch(REG8(AL)) {
11693: case 0x00:
1.1.1.14 root 11694: if(no_windows) {
1.1.1.29 root 11695: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
11696: // REG8(AL) = 0x00;
1.1.1.14 root 11697: } else {
1.1.1.30 root 11698: REG8(AL) = win_major_version;
11699: REG8(AH) = win_minor_version;
1.1 root 11700: }
11701: break;
1.1.1.30 root 11702: case 0x05:
11703: // from DOSBox
11704: i386_set_a20_line(1);
11705: break;
1.1.1.22 root 11706: case 0x0a:
11707: if(!no_windows) {
11708: REG16(AX) = 0x0000;
1.1.1.30 root 11709: REG8(BH) = win_major_version;
11710: REG8(BL) = win_minor_version;
1.1.1.22 root 11711: REG16(CX) = 0x0003; // enhanced
11712: }
11713: break;
1.1.1.30 root 11714: case 0x0b:
11715: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 11716: case 0x0e:
11717: case 0x0f:
1.1.1.30 root 11718: case 0x10:
1.1.1.22 root 11719: case 0x11:
11720: case 0x12:
11721: case 0x13:
11722: case 0x14:
1.1.1.30 root 11723: case 0x15:
1.1.1.33 root 11724: case 0x86:
1.1.1.22 root 11725: case 0x87:
1.1.1.30 root 11726: case 0x89:
1.1.1.33 root 11727: case 0x8a:
1.1.1.22 root 11728: // function not supported, do not clear AX
11729: break;
1.1.1.14 root 11730: case 0x80:
11731: Sleep(10);
1.1.1.35 root 11732: REQUEST_HARDWRE_UPDATE();
1.1.1.29 root 11733: REG8(AL) = 0x00;
1.1.1.14 root 11734: break;
1.1.1.33 root 11735: case 0x83:
11736: REG16(BX) = 0x01; // system vm id
11737: break;
1.1.1.22 root 11738: case 0x8e:
11739: REG16(AX) = 0x00; // failed
11740: break;
1.1.1.20 root 11741: case 0x8f:
11742: switch(REG8(DH)) {
11743: case 0x00:
11744: case 0x02:
11745: case 0x03:
11746: REG16(AX) = 0x00;
11747: break;
11748: case 0x01:
11749: REG16(AX) = 0x168f;
11750: break;
11751: }
11752: break;
1.1 root 11753: default:
1.1.1.22 root 11754: 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));
11755: REG16(AX) = 0x01;
11756: m_CF = 1;
11757: break;
11758: }
11759: }
11760:
11761: inline void msdos_int_2fh_19h()
11762: {
11763: switch(REG8(AL)) {
11764: case 0x00:
1.1.1.29 root 11765: // SHELLB.COM is not installed
11766: // REG8(AL) = 0x00;
1.1.1.22 root 11767: break;
11768: case 0x01:
11769: case 0x02:
11770: case 0x03:
11771: case 0x04:
11772: REG16(AX) = 0x01;
11773: m_CF = 1;
11774: break;
1.1.1.29 root 11775: case 0x80:
11776: // IBM ROM-DOS v4.0 is not installed
11777: // REG8(AL) = 0x00;
11778: break;
1.1.1.22 root 11779: default:
11780: 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 11781: REG16(AX) = 0x01;
1.1.1.3 root 11782: m_CF = 1;
1.1 root 11783: break;
11784: }
11785: }
11786:
11787: inline void msdos_int_2fh_1ah()
11788: {
11789: switch(REG8(AL)) {
11790: case 0x00:
1.1.1.29 root 11791: // ANSI.SYS is installed
1.1 root 11792: REG8(AL) = 0xff;
11793: break;
11794: default:
1.1.1.22 root 11795: 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));
11796: REG16(AX) = 0x01;
11797: m_CF = 1;
11798: break;
11799: }
11800: }
11801:
1.1.1.30 root 11802: inline void msdos_int_2fh_40h()
1.1.1.22 root 11803: {
11804: switch(REG8(AL)) {
11805: case 0x00:
1.1.1.30 root 11806: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
11807: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 11808: break;
11809: default:
11810: 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 11811: REG16(AX) = 0x01;
1.1.1.3 root 11812: m_CF = 1;
1.1 root 11813: break;
11814: }
11815: }
11816:
11817: inline void msdos_int_2fh_43h()
11818: {
11819: switch(REG8(AL)) {
11820: case 0x00:
1.1.1.29 root 11821: // XMS is installed ?
1.1.1.19 root 11822: #ifdef SUPPORT_XMS
11823: if(support_xms) {
11824: REG8(AL) = 0x80;
11825: } else
11826: #endif
11827: REG8(AL) = 0x00;
11828: break;
11829: case 0x10:
11830: SREG(ES) = XMS_TOP >> 4;
11831: i386_load_segment_descriptor(ES);
1.1.1.26 root 11832: REG16(BX) = 0x15;
1.1 root 11833: break;
11834: default:
1.1.1.22 root 11835: 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));
11836: REG16(AX) = 0x01;
11837: m_CF = 1;
11838: break;
11839: }
11840: }
11841:
11842: inline void msdos_int_2fh_46h()
11843: {
11844: switch(REG8(AL)) {
11845: case 0x80:
1.1.1.29 root 11846: // Windows v3.0 is not installed
11847: // REG8(AL) = 0x00;
1.1.1.22 root 11848: break;
11849: default:
11850: 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));
11851: REG16(AX) = 0x01;
11852: m_CF = 1;
11853: break;
11854: }
11855: }
11856:
11857: inline void msdos_int_2fh_48h()
11858: {
11859: switch(REG8(AL)) {
11860: case 0x00:
1.1.1.29 root 11861: // DOSKEY is not installed
11862: // REG8(AL) = 0x00;
1.1.1.22 root 11863: break;
11864: case 0x10:
11865: msdos_int_21h_0ah();
11866: REG16(AX) = 0x00;
11867: break;
11868: default:
11869: 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 11870: REG16(AX) = 0x01;
1.1.1.3 root 11871: m_CF = 1;
1.1 root 11872: break;
11873: }
11874: }
11875:
11876: inline void msdos_int_2fh_4ah()
11877: {
11878: switch(REG8(AL)) {
1.1.1.29 root 11879: #ifdef SUPPORT_HMA
11880: case 0x01: // DOS 5.0+ - Query Free HMA Space
11881: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
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: }
11886: int offset = 0xffff;
11887: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
11888: REG16(DI) = offset + 0x10;
11889: } else {
11890: REG16(DI) = 0xffff;
11891: }
11892: } else {
11893: // HMA is already used
11894: REG16(BX) = 0;
11895: REG16(DI) = 0xffff;
11896: }
11897: SREG(ES) = 0xffff;
11898: i386_load_segment_descriptor(ES);
11899: break;
11900: case 0x02: // DOS 5.0+ - Allocate HMA Space
11901: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
11902: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11903: // restore first free mcb in high memory area
11904: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11905: }
11906: int size = REG16(BX), offset;
11907: if((size % 16) != 0) {
11908: size &= ~15;
11909: size += 16;
11910: }
11911: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
11912: REG16(BX) = size;
11913: REG16(DI) = offset + 0x10;
11914: is_hma_used_by_int_2fh = true;
11915: } else {
11916: REG16(BX) = 0;
11917: REG16(DI) = 0xffff;
11918: }
11919: } else {
11920: // HMA is already used
11921: REG16(BX) = 0;
11922: REG16(DI) = 0xffff;
11923: }
11924: SREG(ES) = 0xffff;
11925: i386_load_segment_descriptor(ES);
11926: break;
11927: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
11928: if(REG8(DL) == 0x00) {
11929: if(!is_hma_used_by_xms) {
11930: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11931: // restore first free mcb in high memory area
11932: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11933: is_hma_used_by_int_2fh = false;
11934: }
11935: int size = REG16(BX), offset;
11936: if((size % 16) != 0) {
11937: size &= ~15;
11938: size += 16;
11939: }
11940: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
11941: // REG16(BX) = size;
11942: SREG(ES) = 0xffff;
11943: i386_load_segment_descriptor(ES);
11944: REG16(DI) = offset + 0x10;
11945: is_hma_used_by_int_2fh = true;
11946: } else {
11947: REG16(DI) = 0xffff;
11948: }
11949: } else {
11950: REG16(DI) = 0xffff;
11951: }
11952: } else if(REG8(DL) == 0x01) {
11953: if(!is_hma_used_by_xms) {
11954: int size = REG16(BX);
11955: if((size % 16) != 0) {
11956: size &= ~15;
11957: size += 16;
11958: }
11959: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
11960: // memory block address is not changed
11961: } else {
11962: REG16(DI) = 0xffff;
11963: }
11964: } else {
11965: REG16(DI) = 0xffff;
11966: }
11967: } else if(REG8(DL) == 0x02) {
11968: if(!is_hma_used_by_xms) {
11969: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11970: // restore first free mcb in high memory area
11971: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11972: is_hma_used_by_int_2fh = false;
11973: } else {
11974: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
11975: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
11976: is_hma_used_by_int_2fh = false;
11977: }
11978: }
11979: }
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: }
11985: break;
11986: case 0x04: // Windows95 - Get Start of HMA Memory Chain
11987: if(!is_hma_used_by_xms) {
11988: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11989: // restore first free mcb in high memory area
11990: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11991: is_hma_used_by_int_2fh = false;
11992: }
11993: REG16(AX) = 0x0000;
11994: SREG(ES) = 0xffff;
11995: i386_load_segment_descriptor(ES);
11996: REG16(DI) = 0x10;
11997: }
11998: break;
11999: #else
1.1 root 12000: case 0x01:
12001: case 0x02:
1.1.1.29 root 12002: // HMA is already used
1.1.1.27 root 12003: REG16(BX) = 0x0000;
1.1.1.3 root 12004: SREG(ES) = 0xffff;
12005: i386_load_segment_descriptor(ES);
1.1 root 12006: REG16(DI) = 0xffff;
12007: break;
1.1.1.19 root 12008: case 0x03:
12009: // unable to allocate
12010: REG16(DI) = 0xffff;
12011: break;
12012: case 0x04:
12013: // function not supported, do not clear AX
12014: break;
1.1.1.29 root 12015: #endif
12016: case 0x10:
12017: if(REG16(BX) == 0x0000) {
12018: // SMARTDRV is not installed
12019: } else {
12020: 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));
12021: REG16(AX) = 0x01;
12022: m_CF = 1;
12023: }
12024: break;
12025: case 0x11:
12026: if(REG16(BX) == 0x0000) {
12027: // DBLSPACE.BIN is not installed
12028: } else {
12029: 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));
12030: REG16(AX) = 0x01;
12031: m_CF = 1;
12032: }
1.1.1.22 root 12033: break;
12034: default:
12035: 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));
12036: REG16(AX) = 0x01;
12037: m_CF = 1;
12038: break;
12039: }
12040: }
12041:
12042: inline void msdos_int_2fh_4bh()
12043: {
12044: switch(REG8(AL)) {
1.1.1.24 root 12045: case 0x01:
1.1.1.22 root 12046: case 0x02:
1.1.1.29 root 12047: // Task Switcher is not installed
1.1.1.24 root 12048: break;
12049: case 0x03:
12050: // this call is available from within DOSSHELL even if the task switcher is not installed
12051: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 12052: break;
1.1.1.30 root 12053: case 0x04:
12054: REG16(BX) = 0x0000; // free switcher id successfully
12055: break;
1.1 root 12056: default:
1.1.1.22 root 12057: 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 12058: REG16(AX) = 0x01;
1.1.1.3 root 12059: m_CF = 1;
1.1 root 12060: break;
12061: }
12062: }
12063:
12064: inline void msdos_int_2fh_4fh()
12065: {
12066: switch(REG8(AL)) {
12067: case 0x00:
1.1.1.29 root 12068: // BILING is installed
1.1.1.27 root 12069: REG16(AX) = 0x0000;
12070: REG8(DL) = 0x01; // major version
12071: REG8(DH) = 0x00; // minor version
1.1 root 12072: break;
12073: case 0x01:
1.1.1.27 root 12074: REG16(AX) = 0x0000;
1.1 root 12075: REG16(BX) = active_code_page;
12076: break;
12077: default:
1.1.1.22 root 12078: 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));
12079: REG16(AX) = 0x01;
12080: m_CF = 1;
12081: break;
12082: }
12083: }
12084:
12085: inline void msdos_int_2fh_55h()
12086: {
12087: switch(REG8(AL)) {
12088: case 0x00:
12089: case 0x01:
12090: // 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));
12091: break;
12092: default:
12093: 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 12094: REG16(AX) = 0x01;
1.1.1.3 root 12095: m_CF = 1;
1.1 root 12096: break;
12097: }
12098: }
12099:
1.1.1.24 root 12100: inline void msdos_int_2fh_adh()
12101: {
12102: switch(REG8(AL)) {
12103: case 0x00:
1.1.1.29 root 12104: // DISPLAY.SYS is installed
1.1.1.24 root 12105: REG8(AL) = 0xff;
12106: REG16(BX) = 0x100; // ???
12107: break;
12108: case 0x01:
12109: active_code_page = REG16(BX);
12110: msdos_nls_tables_update();
12111: REG16(AX) = 0x01;
12112: break;
12113: case 0x02:
12114: REG16(BX) = active_code_page;
12115: break;
12116: case 0x03:
12117: // FIXME
12118: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
12119: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
12120: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
12121: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
12122: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
12123: break;
12124: case 0x80:
12125: break; // keyb.com is not installed
12126: default:
12127: 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));
12128: REG16(AX) = 0x01;
12129: m_CF = 1;
12130: break;
12131: }
12132: }
12133:
1.1 root 12134: inline void msdos_int_2fh_aeh()
12135: {
12136: switch(REG8(AL)) {
12137: case 0x00:
1.1.1.28 root 12138: // FIXME: we need to check the given command line
12139: REG8(AL) = 0x00; // the command should be executed as usual
12140: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 12141: break;
12142: case 0x01:
12143: {
12144: char command[MAX_PATH];
12145: memset(command, 0, sizeof(command));
1.1.1.3 root 12146: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 12147:
12148: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
12149: param->env_seg = 0;
12150: param->cmd_line.w.l = 44;
12151: param->cmd_line.w.h = (WORK_TOP >> 4);
12152: param->fcb1.w.l = 24;
12153: param->fcb1.w.h = (WORK_TOP >> 4);
12154: param->fcb2.w.l = 24;
12155: param->fcb2.w.h = (WORK_TOP >> 4);
12156:
12157: memset(mem + WORK_TOP + 24, 0x20, 20);
12158:
12159: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 12160: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
12161: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 12162: cmd_line->cmd[cmd_line->len] = 0x0d;
12163:
1.1.1.28 root 12164: try {
12165: msdos_process_exec(command, param, 0);
12166: } catch(...) {
12167: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 12168: }
12169: }
12170: break;
12171: default:
1.1.1.22 root 12172: 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 12173: REG16(AX) = 0x01;
1.1.1.3 root 12174: m_CF = 1;
1.1 root 12175: break;
12176: }
12177: }
12178:
1.1.1.34 root 12179: inline void msdos_int_2fh_b7h()
12180: {
12181: switch(REG8(AL)) {
12182: case 0x00:
12183: // APPEND is not installed
12184: // REG8(AL) = 0x00;
12185: break;
12186: case 0x07:
12187: // COMMAND.COM calls this service without checking APPEND is installed
12188: break;
12189: default:
12190: 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));
12191: REG16(AX) = 0x01;
12192: m_CF = 1;
12193: break;
12194: }
12195: }
12196:
1.1.1.24 root 12197: inline void msdos_int_33h_0000h()
12198: {
12199: REG16(AX) = 0xffff; // hardware/driver installed
12200: REG16(BX) = MAX_MOUSE_BUTTONS;
12201: }
12202:
12203: inline void msdos_int_33h_0001h()
12204: {
1.1.1.34 root 12205: if(mouse.hidden > 0) {
12206: mouse.hidden--;
12207: }
12208: if(mouse.hidden == 0) {
1.1.1.24 root 12209: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
12210: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
12211: }
12212: pic[1].imr &= ~0x10; // enable irq12
12213: }
12214: }
12215:
12216: inline void msdos_int_33h_0002h()
12217: {
1.1.1.34 root 12218: mouse.hidden++;
12219: // SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode & ~ENABLE_MOUSE_INPUT);
12220: pic[1].imr |= 0x10; // enable irq12
1.1.1.24 root 12221: }
12222:
12223: inline void msdos_int_33h_0003h()
12224: {
1.1.1.34 root 12225: // if(mouse.hidden > 0) {
12226: update_console_input();
12227: // }
1.1.1.24 root 12228: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 12229: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
12230: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
12231: }
12232:
12233: inline void msdos_int_33h_0004h()
12234: {
12235: mouse.position.x = REG16(CX);
12236: mouse.position.x = REG16(DX);
1.1.1.24 root 12237: }
12238:
12239: inline void msdos_int_33h_0005h()
12240: {
1.1.1.34 root 12241: // if(mouse.hidden > 0) {
12242: update_console_input();
12243: // }
1.1.1.24 root 12244: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
12245: int idx = REG16(BX);
1.1.1.34 root 12246: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff);
12247: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x));
12248: 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 12249: mouse.buttons[idx].pressed_times = 0;
12250: } else {
12251: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
12252: }
12253: REG16(AX) = mouse.get_buttons();
12254: }
12255:
12256: inline void msdos_int_33h_0006h()
12257: {
1.1.1.34 root 12258: // if(mouse.hidden > 0) {
12259: update_console_input();
12260: // }
1.1.1.24 root 12261: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
12262: int idx = REG16(BX);
1.1.1.34 root 12263: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff);
12264: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x));
12265: 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 12266: mouse.buttons[idx].released_times = 0;
12267: } else {
12268: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
12269: }
12270: REG16(AX) = mouse.get_buttons();
12271: }
12272:
12273: inline void msdos_int_33h_0007h()
12274: {
12275: mouse.min_position.x = min(REG16(CX), REG16(DX));
12276: mouse.max_position.x = max(REG16(CX), REG16(DX));
12277: }
12278:
12279: inline void msdos_int_33h_0008h()
12280: {
12281: mouse.min_position.y = min(REG16(CX), REG16(DX));
12282: mouse.max_position.y = max(REG16(CX), REG16(DX));
12283: }
12284:
12285: inline void msdos_int_33h_0009h()
12286: {
12287: mouse.hot_spot[0] = REG16(BX);
12288: mouse.hot_spot[1] = REG16(CX);
12289: }
12290:
12291: inline void msdos_int_33h_000bh()
12292: {
1.1.1.34 root 12293: // if(mouse.hidden > 0) {
12294: update_console_input();
12295: // }
1.1.1.24 root 12296: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
12297: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
12298: mouse.prev_position.x = mouse.position.x;
12299: mouse.prev_position.y = mouse.position.y;
12300: REG16(CX) = dx;
12301: REG16(DX) = dy;
12302: }
12303:
12304: inline void msdos_int_33h_000ch()
12305: {
12306: mouse.call_mask = REG16(CX);
12307: mouse.call_addr.w.l = REG16(DX);
12308: mouse.call_addr.w.h = SREG(ES);
12309: }
12310:
12311: inline void msdos_int_33h_000fh()
12312: {
12313: mouse.mickey.x = REG16(CX);
12314: mouse.mickey.y = REG16(DX);
12315: }
12316:
12317: inline void msdos_int_33h_0011h()
12318: {
12319: REG16(AX) = 0xffff;
12320: REG16(BX) = MAX_MOUSE_BUTTONS;
12321: }
12322:
12323: inline void msdos_int_33h_0014h()
12324: {
12325: UINT16 old_mask = mouse.call_mask;
12326: UINT16 old_ofs = mouse.call_addr.w.l;
12327: UINT16 old_seg = mouse.call_addr.w.h;
12328:
12329: mouse.call_mask = REG16(CX);
12330: mouse.call_addr.w.l = REG16(DX);
12331: mouse.call_addr.w.h = SREG(ES);
12332:
12333: REG16(CX) = old_mask;
12334: REG16(DX) = old_ofs;
12335: SREG(ES) = old_seg;
12336: i386_load_segment_descriptor(ES);
12337: }
12338:
12339: inline void msdos_int_33h_0015h()
12340: {
12341: REG16(BX) = sizeof(mouse);
12342: }
12343:
12344: inline void msdos_int_33h_0016h()
12345: {
12346: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
12347: }
12348:
12349: inline void msdos_int_33h_0017h()
12350: {
12351: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
12352: }
12353:
12354: inline void msdos_int_33h_001ah()
12355: {
12356: mouse.sensitivity[0] = REG16(BX);
12357: mouse.sensitivity[1] = REG16(CX);
12358: mouse.sensitivity[2] = REG16(DX);
12359: }
12360:
12361: inline void msdos_int_33h_001bh()
12362: {
12363: REG16(BX) = mouse.sensitivity[0];
12364: REG16(CX) = mouse.sensitivity[1];
12365: REG16(DX) = mouse.sensitivity[2];
12366: }
12367:
12368: inline void msdos_int_33h_001dh()
12369: {
12370: mouse.display_page = REG16(BX);
12371: }
12372:
12373: inline void msdos_int_33h_001eh()
12374: {
12375: REG16(BX) = mouse.display_page;
12376: }
12377:
1.1.1.34 root 12378: inline void msdos_int_33h_001fh()
12379: {
12380: // from DOSBox
12381: REG16(BX) = 0x0000;
12382: SREG(ES) = 0x0000;
12383: i386_load_segment_descriptor(ES);
12384: mouse.enabled = false;
12385: mouse.old_hidden = mouse.hidden;
12386: mouse.hidden = 1;
12387: }
12388:
12389: inline void msdos_int_33h_0020h()
12390: {
12391: // from DOSBox
12392: mouse.enabled = true;
12393: mouse.hidden = mouse.old_hidden;
12394: }
12395:
1.1.1.24 root 12396: inline void msdos_int_33h_0021h()
12397: {
12398: REG16(AX) = 0xffff;
12399: REG16(BX) = MAX_MOUSE_BUTTONS;
12400: }
12401:
12402: inline void msdos_int_33h_0022h()
12403: {
12404: mouse.language = REG16(BX);
12405: }
12406:
12407: inline void msdos_int_33h_0023h()
12408: {
12409: REG16(BX) = mouse.language;
12410: }
12411:
12412: inline void msdos_int_33h_0024h()
12413: {
12414: REG16(BX) = 0x0805; // V8.05
12415: REG16(CX) = 0x0400; // PS/2
12416: }
12417:
12418: inline void msdos_int_33h_0026h()
12419: {
12420: REG16(BX) = 0x0000;
12421: REG16(CX) = mouse.max_position.x;
12422: REG16(DX) = mouse.max_position.y;
12423: }
12424:
12425: inline void msdos_int_33h_002ah()
12426: {
1.1.1.34 root 12427: REG16(AX) = -mouse.hidden;
1.1.1.24 root 12428: REG16(BX) = mouse.hot_spot[0];
12429: REG16(CX) = mouse.hot_spot[1];
12430: REG16(DX) = 4; // PS/2
12431: }
12432:
12433: inline void msdos_int_33h_0031h()
12434: {
12435: REG16(AX) = mouse.min_position.x;
12436: REG16(BX) = mouse.min_position.y;
12437: REG16(CX) = mouse.max_position.x;
12438: REG16(DX) = mouse.max_position.y;
12439: }
12440:
12441: inline void msdos_int_33h_0032h()
12442: {
12443: REG16(AX) = 0;
12444: // REG16(AX) |= 0x8000; // 0025h
12445: REG16(AX) |= 0x4000; // 0026h
12446: // REG16(AX) |= 0x2000; // 0027h
12447: // REG16(AX) |= 0x1000; // 0028h
12448: // REG16(AX) |= 0x0800; // 0029h
12449: REG16(AX) |= 0x0400; // 002ah
12450: // REG16(AX) |= 0x0200; // 002bh
12451: // REG16(AX) |= 0x0100; // 002ch
12452: // REG16(AX) |= 0x0080; // 002dh
12453: // REG16(AX) |= 0x0040; // 002eh
12454: REG16(AX) |= 0x0020; // 002fh
12455: // REG16(AX) |= 0x0010; // 0030h
12456: REG16(AX) |= 0x0008; // 0031h
12457: REG16(AX) |= 0x0004; // 0032h
12458: // REG16(AX) |= 0x0002; // 0033h
12459: // REG16(AX) |= 0x0001; // 0034h
12460: }
12461:
1.1.1.19 root 12462: inline void msdos_int_67h_40h()
12463: {
12464: if(!support_ems) {
12465: REG8(AH) = 0x84;
12466: } else {
12467: REG8(AH) = 0x00;
12468: }
12469: }
12470:
12471: inline void msdos_int_67h_41h()
12472: {
12473: if(!support_ems) {
12474: REG8(AH) = 0x84;
12475: } else {
12476: REG8(AH) = 0x00;
12477: REG16(BX) = EMS_TOP >> 4;
12478: }
12479: }
12480:
12481: inline void msdos_int_67h_42h()
12482: {
12483: if(!support_ems) {
12484: REG8(AH) = 0x84;
12485: } else {
12486: REG8(AH) = 0x00;
12487: REG16(BX) = free_ems_pages;
12488: REG16(DX) = MAX_EMS_PAGES;
12489: }
12490: }
12491:
12492: inline void msdos_int_67h_43h()
12493: {
12494: if(!support_ems) {
12495: REG8(AH) = 0x84;
12496: } else if(REG16(BX) > MAX_EMS_PAGES) {
12497: REG8(AH) = 0x87;
12498: } else if(REG16(BX) > free_ems_pages) {
12499: REG8(AH) = 0x88;
12500: } else if(REG16(BX) == 0) {
12501: REG8(AH) = 0x89;
12502: } else {
1.1.1.31 root 12503: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12504: if(!ems_handles[i].allocated) {
12505: ems_allocate_pages(i, REG16(BX));
12506: REG8(AH) = 0x00;
12507: REG16(DX) = i;
12508: return;
12509: }
12510: }
12511: REG8(AH) = 0x85;
12512: }
12513: }
12514:
12515: inline void msdos_int_67h_44h()
12516: {
12517: if(!support_ems) {
12518: REG8(AH) = 0x84;
1.1.1.31 root 12519: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12520: REG8(AH) = 0x83;
12521: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
12522: REG8(AH) = 0x8a;
12523: // } else if(!(REG8(AL) < 4)) {
12524: // REG8(AH) = 0x8b;
12525: } else if(REG16(BX) == 0xffff) {
12526: ems_unmap_page(REG8(AL) & 3);
12527: REG8(AH) = 0x00;
12528: } else {
12529: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
12530: REG8(AH) = 0x00;
12531: }
12532: }
12533:
12534: inline void msdos_int_67h_45h()
12535: {
12536: if(!support_ems) {
12537: REG8(AH) = 0x84;
1.1.1.31 root 12538: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12539: REG8(AH) = 0x83;
12540: } else {
12541: ems_release_pages(REG16(DX));
12542: REG8(AH) = 0x00;
12543: }
12544: }
12545:
12546: inline void msdos_int_67h_46h()
12547: {
12548: if(!support_ems) {
12549: REG8(AH) = 0x84;
12550: } else {
1.1.1.29 root 12551: // REG16(AX) = 0x0032; // EMS 3.2
12552: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 12553: }
12554: }
12555:
12556: inline void msdos_int_67h_47h()
12557: {
12558: // NOTE: the map data should be stored in the specified ems page, not process data
12559: process_t *process = msdos_process_info_get(current_psp);
12560:
12561: if(!support_ems) {
12562: REG8(AH) = 0x84;
1.1.1.31 root 12563: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12564: // REG8(AH) = 0x83;
12565: } else if(process->ems_pages_stored) {
12566: REG8(AH) = 0x8d;
12567: } else {
12568: for(int i = 0; i < 4; i++) {
12569: process->ems_pages[i].handle = ems_pages[i].handle;
12570: process->ems_pages[i].page = ems_pages[i].page;
12571: process->ems_pages[i].mapped = ems_pages[i].mapped;
12572: }
12573: process->ems_pages_stored = true;
12574: REG8(AH) = 0x00;
12575: }
12576: }
12577:
12578: inline void msdos_int_67h_48h()
12579: {
12580: // NOTE: the map data should be restored from the specified ems page, not process data
12581: process_t *process = msdos_process_info_get(current_psp);
12582:
12583: if(!support_ems) {
12584: REG8(AH) = 0x84;
1.1.1.31 root 12585: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12586: // REG8(AH) = 0x83;
12587: } else if(!process->ems_pages_stored) {
12588: REG8(AH) = 0x8e;
12589: } else {
12590: for(int i = 0; i < 4; i++) {
12591: if(process->ems_pages[i].mapped) {
12592: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
12593: } else {
12594: ems_unmap_page(i);
12595: }
12596: }
12597: process->ems_pages_stored = false;
12598: REG8(AH) = 0x00;
12599: }
12600: }
12601:
12602: inline void msdos_int_67h_4bh()
12603: {
12604: if(!support_ems) {
12605: REG8(AH) = 0x84;
12606: } else {
12607: REG8(AH) = 0x00;
12608: REG16(BX) = 0;
1.1.1.31 root 12609: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12610: if(ems_handles[i].allocated) {
12611: REG16(BX)++;
12612: }
12613: }
12614: }
12615: }
12616:
12617: inline void msdos_int_67h_4ch()
12618: {
12619: if(!support_ems) {
12620: REG8(AH) = 0x84;
1.1.1.31 root 12621: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12622: REG8(AH) = 0x83;
12623: } else {
12624: REG8(AH) = 0x00;
12625: REG16(BX) = ems_handles[REG16(DX)].pages;
12626: }
12627: }
12628:
12629: inline void msdos_int_67h_4dh()
12630: {
12631: if(!support_ems) {
12632: REG8(AH) = 0x84;
12633: } else {
12634: REG8(AH) = 0x00;
12635: REG16(BX) = 0;
1.1.1.31 root 12636: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12637: if(ems_handles[i].allocated) {
12638: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
12639: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
12640: REG16(BX)++;
12641: }
12642: }
12643: }
12644: }
12645:
1.1.1.20 root 12646: inline void msdos_int_67h_4eh()
12647: {
12648: if(!support_ems) {
12649: REG8(AH) = 0x84;
12650: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
12651: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
12652: // save page map
12653: for(int i = 0; i < 4; i++) {
12654: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
12655: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
12656: }
12657: }
12658: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
12659: // restore page map
12660: for(int i = 0; i < 4; i++) {
12661: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
12662: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
12663:
1.1.1.31 root 12664: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 12665: ems_map_page(i, handle, page);
12666: } else {
12667: ems_unmap_page(i);
12668: }
12669: }
12670: }
12671: REG8(AH) = 0x00;
12672: } else if(REG8(AL) == 0x03) {
12673: REG8(AH) = 0x00;
1.1.1.21 root 12674: REG8(AL) = 4 * 4;
12675: } else {
1.1.1.22 root 12676: 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 12677: REG8(AH) = 0x8f;
12678: }
12679: }
12680:
12681: inline void msdos_int_67h_4fh()
12682: {
12683: if(!support_ems) {
12684: REG8(AH) = 0x84;
12685: } else if(REG8(AL) == 0x00) {
12686: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
12687:
12688: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
12689: for(int i = 0; i < count; i++) {
12690: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
12691: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
12692:
12693: // if(!(physical < 4)) {
12694: // REG8(AH) = 0x8b;
12695: // return;
12696: // }
12697: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
12698: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
12699: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
12700: }
12701: REG8(AH) = 0x00;
12702: } else if(REG8(AL) == 0x01) {
12703: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
12704:
12705: for(int i = 0; i < count; i++) {
12706: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
12707: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
12708: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
12709: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
12710:
12711: // if(!(physical < 4)) {
12712: // REG8(AH) = 0x8b;
12713: // return;
12714: // } else
1.1.1.31 root 12715: if(!(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
1.1.1.21 root 12716: REG8(AH) = 0x83;
12717: return;
12718: } else if(logical == 0xffff) {
12719: ems_unmap_page(physical & 3);
12720: } else if(logical < ems_handles[handle].pages) {
12721: ems_map_page(physical & 3, handle, logical);
12722: } else {
12723: REG8(AH) = 0x8a;
12724: return;
12725: }
12726: }
12727: REG8(AH) = 0x00;
12728: } else if(REG8(AL) == 0x02) {
12729: REG8(AH) = 0x00;
12730: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 12731: } else {
1.1.1.22 root 12732: 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 12733: REG8(AH) = 0x8f;
12734: }
12735: }
12736:
12737: inline void msdos_int_67h_50h()
12738: {
12739: if(!support_ems) {
12740: REG8(AH) = 0x84;
1.1.1.31 root 12741: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 12742: REG8(AH) = 0x83;
12743: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
12744: for(int i = 0; i < REG16(CX); i++) {
12745: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
12746: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
12747:
12748: if(REG8(AL) == 0x01) {
12749: physical = ((physical << 4) - EMS_TOP) / 0x4000;
12750: }
12751: // if(!(physical < 4)) {
12752: // REG8(AH) = 0x8b;
12753: // return;
12754: // } else
12755: if(logical == 0xffff) {
12756: ems_unmap_page(physical & 3);
12757: } else if(logical < ems_handles[REG16(DX)].pages) {
12758: ems_map_page(physical & 3, REG16(DX), logical);
12759: } else {
12760: REG8(AH) = 0x8a;
12761: return;
12762: }
12763: }
12764: REG8(AH) = 0x00;
12765: } else {
1.1.1.22 root 12766: 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 12767: REG8(AH) = 0x8f;
12768: }
12769: }
12770:
1.1.1.19 root 12771: inline void msdos_int_67h_51h()
12772: {
12773: if(!support_ems) {
12774: REG8(AH) = 0x84;
1.1.1.31 root 12775: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12776: REG8(AH) = 0x83;
12777: } else if(REG16(BX) > MAX_EMS_PAGES) {
12778: REG8(AH) = 0x87;
12779: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
12780: REG8(AH) = 0x88;
12781: } else {
12782: ems_reallocate_pages(REG16(DX), REG16(BX));
12783: REG8(AH) = 0x00;
12784: }
12785: }
12786:
1.1.1.20 root 12787: inline void msdos_int_67h_52h()
12788: {
12789: if(!support_ems) {
12790: REG8(AH) = 0x84;
1.1.1.31 root 12791: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
12792: // REG8(AH) = 0x83;
1.1.1.20 root 12793: } else if(REG8(AL) == 0x00) {
12794: REG8(AL) = 0x00; // handle is volatile
12795: REG8(AH) = 0x00;
12796: } else if(REG8(AL) == 0x01) {
12797: if(REG8(BL) == 0x00) {
12798: REG8(AH) = 0x00;
12799: } else {
12800: REG8(AH) = 0x90; // undefined attribute type
12801: }
12802: } else if(REG8(AL) == 0x02) {
12803: REG8(AL) = 0x00; // only volatile handles supported
12804: REG8(AH) = 0x00;
12805: } else {
1.1.1.22 root 12806: 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 12807: REG8(AH) = 0x8f;
12808: }
12809: }
12810:
1.1.1.19 root 12811: inline void msdos_int_67h_53h()
12812: {
12813: if(!support_ems) {
12814: REG8(AH) = 0x84;
1.1.1.31 root 12815: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12816: REG8(AH) = 0x83;
12817: } else if(REG8(AL) == 0x00) {
12818: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
12819: REG8(AH) = 0x00;
12820: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 12821: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12822: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
12823: REG8(AH) = 0xa1;
12824: return;
12825: }
12826: }
12827: REG8(AH) = 0x00;
12828: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
12829: } else {
1.1.1.22 root 12830: 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 12831: REG8(AH) = 0x8f;
1.1.1.19 root 12832: }
12833: }
12834:
12835: inline void msdos_int_67h_54h()
12836: {
12837: if(!support_ems) {
12838: REG8(AH) = 0x84;
12839: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 12840: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12841: if(ems_handles[i].allocated) {
12842: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
12843: } else {
12844: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
12845: }
12846: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
12847: }
12848: REG8(AH) = 0x00;
12849: REG8(AL) = MAX_EMS_HANDLES;
12850: } else if(REG8(AL) == 0x01) {
12851: REG8(AH) = 0xa0; // not found
1.1.1.31 root 12852: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12853: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
12854: REG8(AH) = 0x00;
12855: REG16(DX) = i;
12856: break;
12857: }
12858: }
12859: } else if(REG8(AL) == 0x02) {
12860: REG8(AH) = 0x00;
12861: REG16(BX) = MAX_EMS_HANDLES;
12862: } else {
1.1.1.22 root 12863: 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 12864: REG8(AH) = 0x8f;
12865: }
12866: }
12867:
12868: inline void msdos_int_67h_57h_tmp()
12869: {
12870: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
12871: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
12872: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
12873: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
12874: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
12875: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
12876: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
12877: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
12878: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
12879:
1.1.1.32 root 12880: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 12881: UINT32 src_addr, dest_addr;
12882: UINT32 src_addr_max, dest_addr_max;
12883:
12884: if(src_type == 0) {
12885: src_buffer = mem;
12886: src_addr = (src_seg << 4) + src_ofs;
12887: src_addr_max = MAX_MEM;
12888: } else {
1.1.1.31 root 12889: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 12890: REG8(AH) = 0x83;
12891: return;
12892: } else if(!(src_seg < ems_handles[src_handle].pages)) {
12893: REG8(AH) = 0x8a;
12894: return;
12895: }
1.1.1.32 root 12896: if(ems_handles[src_handle].buffer != NULL) {
12897: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
12898: }
1.1.1.20 root 12899: src_addr = src_ofs;
1.1.1.32 root 12900: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 12901: }
12902: if(dest_type == 0) {
12903: dest_buffer = mem;
12904: dest_addr = (dest_seg << 4) + dest_ofs;
12905: dest_addr_max = MAX_MEM;
12906: } else {
1.1.1.31 root 12907: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 12908: REG8(AH) = 0x83;
12909: return;
12910: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
12911: REG8(AH) = 0x8a;
12912: return;
12913: }
1.1.1.32 root 12914: if(ems_handles[dest_handle].buffer != NULL) {
12915: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
12916: }
1.1.1.20 root 12917: dest_addr = dest_ofs;
1.1.1.32 root 12918: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 12919: }
1.1.1.32 root 12920: if(src_buffer != NULL && dest_buffer != NULL) {
12921: for(int i = 0; i < copy_length; i++) {
12922: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
12923: if(REG8(AL) == 0x00) {
12924: dest_buffer[dest_addr++] = src_buffer[src_addr++];
12925: } else if(REG8(AL) == 0x01) {
12926: UINT8 tmp = dest_buffer[dest_addr];
12927: dest_buffer[dest_addr++] = src_buffer[src_addr];
12928: src_buffer[src_addr++] = tmp;
12929: }
12930: } else {
12931: REG8(AH) = 0x93;
12932: return;
1.1.1.20 root 12933: }
12934: }
1.1.1.32 root 12935: REG8(AH) = 0x00;
12936: } else {
12937: REG8(AH) = 0x80;
1.1.1.20 root 12938: }
12939: }
12940:
12941: inline void msdos_int_67h_57h()
12942: {
12943: if(!support_ems) {
12944: REG8(AH) = 0x84;
12945: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
12946: struct {
12947: UINT16 handle;
12948: UINT16 page;
12949: bool mapped;
12950: } tmp_pages[4];
12951:
12952: // unmap pages to copy memory data to ems buffer
12953: for(int i = 0; i < 4; i++) {
12954: tmp_pages[i].handle = ems_pages[i].handle;
12955: tmp_pages[i].page = ems_pages[i].page;
12956: tmp_pages[i].mapped = ems_pages[i].mapped;
12957: ems_unmap_page(i);
12958: }
12959:
12960: // run move/exchange operation
12961: msdos_int_67h_57h_tmp();
12962:
12963: // restore unmapped pages
12964: for(int i = 0; i < 4; i++) {
12965: if(tmp_pages[i].mapped) {
12966: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
12967: }
12968: }
12969: } else {
1.1.1.22 root 12970: 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 12971: REG8(AH) = 0x8f;
12972: }
12973: }
12974:
12975: inline void msdos_int_67h_58h()
12976: {
12977: if(!support_ems) {
12978: REG8(AH) = 0x84;
12979: } else if(REG8(AL) == 0x00) {
12980: for(int i = 0; i < 4; i++) {
1.1.1.30 root 12981: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
12982: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 12983: }
12984: REG8(AH) = 0x00;
12985: REG16(CX) = 4;
12986: } else if(REG8(AL) == 0x01) {
12987: REG8(AH) = 0x00;
12988: REG16(CX) = 4;
12989: } else {
1.1.1.22 root 12990: 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 12991: REG8(AH) = 0x8f;
12992: }
12993: }
12994:
12995: inline void msdos_int_67h_5ah()
12996: {
12997: if(!support_ems) {
1.1.1.19 root 12998: REG8(AH) = 0x84;
1.1.1.20 root 12999: } else if(REG16(BX) > MAX_EMS_PAGES) {
13000: REG8(AH) = 0x87;
13001: } else if(REG16(BX) > free_ems_pages) {
13002: REG8(AH) = 0x88;
13003: // } else if(REG16(BX) == 0) {
13004: // REG8(AH) = 0x89;
13005: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 13006: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 13007: if(!ems_handles[i].allocated) {
13008: ems_allocate_pages(i, REG16(BX));
13009: REG8(AH) = 0x00;
13010: REG16(DX) = i;
13011: return;
13012: }
13013: }
13014: REG8(AH) = 0x85;
13015: } else {
1.1.1.22 root 13016: 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 13017: REG8(AH) = 0x8f;
1.1.1.19 root 13018: }
13019: }
13020:
1.1.1.30 root 13021: inline void msdos_int_67h_deh()
13022: {
13023: REG8(AH) = 0x84;
13024: }
13025:
1.1.1.19 root 13026: #ifdef SUPPORT_XMS
13027:
1.1.1.32 root 13028: void msdos_xms_init()
1.1.1.26 root 13029: {
1.1.1.30 root 13030: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
13031: emb_handle_top->address = EMB_TOP;
13032: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 13033: xms_a20_local_enb_count = 0;
13034: }
13035:
1.1.1.32 root 13036: void msdos_xms_finish()
13037: {
13038: msdos_xms_release();
13039: }
13040:
13041: void msdos_xms_release()
1.1.1.30 root 13042: {
13043: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
13044: emb_handle_t *next_handle = emb_handle->next;
13045: free(emb_handle);
13046: emb_handle = next_handle;
13047: }
13048: }
13049:
13050: emb_handle_t *msdos_xms_get_emb_handle(int handle)
13051: {
13052: if(handle != 0) {
13053: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13054: if(emb_handle->handle == handle) {
13055: return(emb_handle);
13056: }
13057: }
13058: }
13059: return(NULL);
13060: }
13061:
13062: int msdos_xms_get_unused_emb_handle_id()
13063: {
13064: for(int handle = 1;; handle++) {
13065: if(msdos_xms_get_emb_handle(handle) == NULL) {
13066: return(handle);
13067: }
13068: }
13069: return(0);
13070: }
13071:
13072: int msdos_xms_get_unused_emb_handle_count()
13073: {
13074: int count = 64; //255;
13075:
13076: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13077: if(emb_handle->handle != 0) {
13078: if(--count == 1) {
13079: break;
13080: }
13081: }
13082: }
13083: return(count);
13084: }
13085:
13086: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
13087: {
13088: if(emb_handle->size_kb > size_kb) {
13089: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
13090:
13091: new_handle->address = emb_handle->address + size_kb * 1024;
13092: new_handle->size_kb = emb_handle->size_kb - size_kb;
13093: emb_handle->size_kb = size_kb;
13094:
13095: new_handle->prev = emb_handle;
13096: new_handle->next = emb_handle->next;
13097: if(emb_handle->next != NULL) {
13098: emb_handle->next->prev = new_handle;
13099: }
13100: emb_handle->next = new_handle;
13101: }
13102: }
13103:
13104: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
13105: {
13106: emb_handle_t *next_handle = emb_handle->next;
13107:
13108: if(next_handle != NULL) {
13109: emb_handle->size_kb += next_handle->size_kb;
13110:
13111: if(next_handle->next != NULL) {
13112: next_handle->next->prev = emb_handle;
13113: }
13114: emb_handle->next = next_handle->next;
13115: free(next_handle);
13116: }
13117: }
13118:
13119: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
13120: {
13121: emb_handle_t *target_handle = NULL;
13122:
13123: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13124: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
13125: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
13126: target_handle = emb_handle;
13127: }
13128: }
13129: }
13130: if(target_handle != NULL) {
13131: if(target_handle->size_kb > size_kb) {
13132: msdos_xms_split_emb_handle(target_handle, size_kb);
13133: }
13134: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
13135: return(target_handle);
13136: }
13137: return(NULL);
13138: }
13139:
13140: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
13141: {
13142: emb_handle_t *prev_handle = emb_handle->prev;
13143: emb_handle_t *next_handle = emb_handle->next;
13144:
13145: if(prev_handle != NULL && prev_handle->handle == 0) {
13146: msdos_xms_combine_emb_handles(prev_handle);
13147: emb_handle = prev_handle;
13148: }
13149: if(next_handle != NULL && next_handle->handle == 0) {
13150: msdos_xms_combine_emb_handles(emb_handle);
13151: }
13152: emb_handle->handle = 0;
13153: }
13154:
1.1.1.19 root 13155: inline void msdos_call_xms_00h()
13156: {
1.1.1.29 root 13157: #if defined(HAS_I386)
13158: REG16(AX) = 0x0300; // V3.00 (XMS Version)
13159: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
13160: #else
13161: REG16(AX) = 0x0200; // V2.00 (XMS Version)
13162: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
13163: #endif
13164: // REG16(DX) = 0x0000; // HMA does not exist
13165: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 13166: }
13167:
13168: inline void msdos_call_xms_01h()
13169: {
1.1.1.29 root 13170: if(REG8(AL) == 0x40) {
13171: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
13172: // DX=KB free extended memory returned by last call of function 08h
13173: REG16(AX) = 0x0000;
13174: REG8(BL) = 0x91;
13175: REG16(DX) = xms_dx_after_call_08h;
13176: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
13177: REG16(AX) = 0x0000;
13178: REG8(BL) = 0x81; // Vdisk was detected
13179: #ifdef SUPPORT_HMA
13180: } else if(is_hma_used_by_int_2fh) {
13181: REG16(AX) = 0x0000;
13182: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
13183: } else if(is_hma_used_by_xms) {
13184: REG16(AX) = 0x0000;
13185: REG8(BL) = 0x91; // HMA is already in use
13186: } else {
13187: REG16(AX) = 0x0001;
13188: is_hma_used_by_xms = true;
13189: #else
13190: } else {
13191: REG16(AX) = 0x0000;
13192: REG8(BL) = 0x91; // HMA is already in use
13193: #endif
13194: }
1.1.1.19 root 13195: }
13196:
13197: inline void msdos_call_xms_02h()
13198: {
1.1.1.29 root 13199: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
13200: REG16(AX) = 0x0000;
13201: REG8(BL) = 0x81; // Vdisk was detected
13202: #ifdef SUPPORT_HMA
13203: } else if(is_hma_used_by_int_2fh) {
13204: REG16(AX) = 0x0000;
13205: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
13206: } else if(!is_hma_used_by_xms) {
13207: REG16(AX) = 0x0000;
13208: REG8(BL) = 0x93; // HMA is not allocated
13209: } else {
13210: REG16(AX) = 0x0001;
13211: is_hma_used_by_xms = false;
13212: // restore first free mcb in high memory area
13213: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13214: #else
13215: } else {
13216: REG16(AX) = 0x0000;
13217: REG8(BL) = 0x91; // HMA is already in use
13218: #endif
13219: }
1.1.1.19 root 13220: }
13221:
13222: inline void msdos_call_xms_03h()
13223: {
13224: i386_set_a20_line(1);
13225: REG16(AX) = 0x0001;
13226: REG8(BL) = 0x00;
13227: }
13228:
13229: inline void msdos_call_xms_04h()
13230: {
1.1.1.21 root 13231: i386_set_a20_line(0);
13232: REG16(AX) = 0x0001;
13233: REG8(BL) = 0x00;
1.1.1.19 root 13234: }
13235:
13236: inline void msdos_call_xms_05h()
13237: {
13238: i386_set_a20_line(1);
13239: REG16(AX) = 0x0001;
13240: REG8(BL) = 0x00;
1.1.1.21 root 13241: xms_a20_local_enb_count++;
1.1.1.19 root 13242: }
13243:
13244: void msdos_call_xms_06h()
13245: {
1.1.1.21 root 13246: if(xms_a20_local_enb_count > 0) {
13247: xms_a20_local_enb_count--;
13248: }
13249: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 13250: i386_set_a20_line(0);
1.1.1.21 root 13251: }
13252: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 13253: REG16(AX) = 0x0000;
13254: REG8(BL) = 0x94;
1.1.1.21 root 13255: } else {
13256: REG16(AX) = 0x0001;
13257: REG8(BL) = 0x00;
1.1.1.19 root 13258: }
13259: }
13260:
13261: inline void msdos_call_xms_07h()
13262: {
13263: REG16(AX) = (m_a20_mask >> 20) & 1;
13264: REG8(BL) = 0x00;
13265: }
13266:
13267: inline void msdos_call_xms_08h()
13268: {
13269: REG16(AX) = REG16(DX) = 0x0000;
13270:
1.1.1.30 root 13271: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13272: if(emb_handle->handle == 0) {
13273: if(REG16(AX) < emb_handle->size_kb) {
13274: REG16(AX) = emb_handle->size_kb;
1.1.1.19 root 13275: }
1.1.1.30 root 13276: REG16(DX) += emb_handle->size_kb;
1.1.1.19 root 13277: }
13278: }
13279:
13280: if(REG16(AX) == 0 && REG16(DX) == 0) {
13281: REG8(BL) = 0xa0;
13282: } else {
13283: REG8(BL) = 0x00;
13284: }
1.1.1.29 root 13285: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 13286: }
13287:
1.1.1.30 root 13288: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 13289: {
1.1.1.30 root 13290: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
13291:
13292: if(emb_handle != NULL) {
13293: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
13294:
13295: REG16(AX) = 0x0001;
13296: REG16(DX) = emb_handle->handle;
13297: REG8(BL) = 0x00;
13298: } else {
13299: REG16(AX) = REG16(DX) = 0x0000;
13300: REG8(BL) = 0xa0;
1.1.1.19 root 13301: }
1.1.1.30 root 13302: }
13303:
13304: inline void msdos_call_xms_09h()
13305: {
13306: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 13307: }
13308:
13309: inline void msdos_call_xms_0ah()
13310: {
1.1.1.30 root 13311: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13312:
13313: if(emb_handle == NULL) {
1.1.1.19 root 13314: REG16(AX) = 0x0000;
13315: REG8(BL) = 0xa2;
1.1.1.30 root 13316: } else if(emb_handle->lock > 0) {
1.1.1.19 root 13317: REG16(AX) = 0x0000;
13318: REG8(BL) = 0xab;
13319: } else {
1.1.1.30 root 13320: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 13321:
13322: REG16(AX) = 0x0001;
13323: REG8(BL) = 0x00;
13324: }
13325: }
13326:
13327: inline void msdos_call_xms_0bh()
13328: {
13329: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
13330: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
13331: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
13332: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
13333: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
13334:
13335: UINT8 *src_buffer, *dest_buffer;
13336: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 13337: emb_handle_t *emb_handle;
1.1.1.19 root 13338:
13339: if(src_handle == 0) {
13340: src_buffer = mem;
13341: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
13342: src_addr_max = MAX_MEM;
1.1.1.30 root 13343:
1.1.1.19 root 13344: } else {
1.1.1.30 root 13345: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 13346: REG16(AX) = 0x0000;
13347: REG8(BL) = 0xa3;
13348: return;
13349: }
1.1.1.30 root 13350: src_buffer = mem + emb_handle->address;
13351: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 13352: }
13353: if(dest_handle == 0) {
13354: dest_buffer = mem;
13355: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
13356: dest_addr_max = MAX_MEM;
13357: } else {
1.1.1.30 root 13358: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 13359: REG16(AX) = 0x0000;
13360: REG8(BL) = 0xa5;
13361: return;
13362: }
1.1.1.30 root 13363: dest_buffer = mem + emb_handle->address;
13364: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 13365: }
13366: for(int i = 0; i < copy_length; i++) {
13367: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
13368: dest_buffer[dest_addr++] = src_buffer[src_addr++];
13369: } else {
13370: break;
13371: }
13372: }
13373: REG16(AX) = 0x0001;
13374: REG8(BL) = 0x00;
13375: }
13376:
13377: inline void msdos_call_xms_0ch()
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;
13384: } else {
1.1.1.30 root 13385: emb_handle->lock++;
1.1.1.19 root 13386: REG16(AX) = 0x0001;
13387: REG8(BL) = 0x00;
1.1.1.30 root 13388: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
13389: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 13390: }
13391: }
13392:
13393: inline void msdos_call_xms_0dh()
13394: {
1.1.1.30 root 13395: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13396:
13397: if(emb_handle == NULL) {
1.1.1.19 root 13398: REG16(AX) = 0x0000;
13399: REG8(BL) = 0xa2;
1.1.1.30 root 13400: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 13401: REG16(AX) = 0x0000;
13402: REG8(BL) = 0xaa;
13403: } else {
1.1.1.30 root 13404: emb_handle->lock--;
1.1.1.19 root 13405: REG16(AX) = 0x0001;
13406: REG8(BL) = 0x00;
13407: }
13408: }
13409:
13410: inline void msdos_call_xms_0eh()
13411: {
1.1.1.30 root 13412: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13413:
13414: if(emb_handle == NULL) {
1.1.1.19 root 13415: REG16(AX) = 0x0000;
13416: REG8(BL) = 0xa2;
13417: } else {
13418: REG16(AX) = 0x0001;
1.1.1.30 root 13419: REG8(BH) = emb_handle->lock;
13420: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
13421: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 13422: }
13423: }
13424:
1.1.1.30 root 13425: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 13426: {
1.1.1.30 root 13427: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13428:
13429: if(emb_handle == NULL) {
1.1.1.19 root 13430: REG16(AX) = 0x0000;
13431: REG8(BL) = 0xa2;
1.1.1.30 root 13432: } else if(emb_handle->lock > 0) {
1.1.1.19 root 13433: REG16(AX) = 0x0000;
13434: REG8(BL) = 0xab;
13435: } else {
1.1.1.30 root 13436: if(emb_handle->size_kb < size_kb) {
13437: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
13438: msdos_xms_combine_emb_handles(emb_handle);
13439: if(emb_handle->size_kb > size_kb) {
13440: msdos_xms_split_emb_handle(emb_handle, size_kb);
13441: }
13442: } else {
13443: int old_handle = emb_handle->handle;
13444: int old_size_kb = emb_handle->size_kb;
13445: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
13446:
13447: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
13448: msdos_xms_free_emb_handle(emb_handle);
13449:
13450: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
13451: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
13452: }
13453: emb_handle->handle = old_handle;
13454: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
13455: free(buffer);
13456: }
13457: } else if(emb_handle->size_kb > size_kb) {
13458: msdos_xms_split_emb_handle(emb_handle, size_kb);
13459: }
13460: if(emb_handle->size_kb != size_kb) {
13461: REG16(AX) = 0x0000;
13462: REG8(BL) = 0xa0;
13463: } else {
13464: REG16(AX) = 0x0001;
13465: REG8(BL) = 0x00;
13466: }
1.1.1.19 root 13467: }
13468: }
13469:
1.1.1.30 root 13470: inline void msdos_call_xms_0fh()
13471: {
13472: msdos_call_xms_0fh(REG16(BX));
13473: }
13474:
1.1.1.19 root 13475: inline void msdos_call_xms_10h()
13476: {
13477: int seg;
13478:
13479: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
13480: REG16(AX) = 0x0001;
13481: REG16(BX) = seg;
13482: } else {
13483: REG16(AX) = 0x0000;
13484: REG8(BL) = 0xb0;
13485: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
13486: }
13487: }
13488:
13489: inline void msdos_call_xms_11h()
13490: {
13491: int mcb_seg = REG16(DX) - 1;
13492: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
13493:
13494: if(mcb->mz == 'M' || mcb->mz == 'Z') {
13495: msdos_mem_free(REG16(DX));
13496: REG16(AX) = 0x0001;
13497: REG8(BL) = 0x00;
13498: } else {
13499: REG16(AX) = 0x0000;
13500: REG8(BL) = 0xb2;
13501: }
13502: }
13503:
13504: inline void msdos_call_xms_12h()
13505: {
13506: int mcb_seg = REG16(DX) - 1;
13507: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
13508: int max_paragraphs;
13509:
13510: if(mcb->mz == 'M' || mcb->mz == 'Z') {
13511: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
13512: REG16(AX) = 0x0001;
13513: REG8(BL) = 0x00;
13514: } else {
13515: REG16(AX) = 0x0000;
13516: REG8(BL) = 0xb0;
13517: REG16(DX) = max_paragraphs;
13518: }
13519: } else {
13520: REG16(AX) = 0x0000;
13521: REG8(BL) = 0xb2;
13522: }
13523: }
13524:
1.1.1.29 root 13525: #if defined(HAS_I386)
13526:
13527: inline void msdos_call_xms_88h()
13528: {
13529: REG32(EAX) = REG32(EDX) = 0x0000;
13530:
1.1.1.30 root 13531: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13532: if(emb_handle->handle == 0) {
13533: if(REG32(EAX) < emb_handle->size_kb) {
13534: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 13535: }
1.1.1.30 root 13536: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 13537: }
13538: }
13539:
13540: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
13541: REG8(BL) = 0xa0;
13542: } else {
13543: REG8(BL) = 0x00;
13544: }
13545: REG32(ECX) = EMB_END - 1;
13546: }
13547:
13548: inline void msdos_call_xms_89h()
13549: {
1.1.1.30 root 13550: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 13551: }
13552:
13553: inline void msdos_call_xms_8eh()
13554: {
1.1.1.30 root 13555: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13556:
13557: if(emb_handle == NULL) {
1.1.1.29 root 13558: REG16(AX) = 0x0000;
13559: REG8(BL) = 0xa2;
13560: } else {
13561: REG16(AX) = 0x0001;
1.1.1.30 root 13562: REG8(BH) = emb_handle->lock;
13563: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
13564: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 13565: }
13566: }
13567:
13568: inline void msdos_call_xms_8fh()
13569: {
1.1.1.30 root 13570: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 13571: }
13572:
13573: #endif
1.1.1.19 root 13574: #endif
13575:
1.1.1.26 root 13576: UINT16 msdos_get_equipment()
13577: {
13578: static UINT16 equip = 0;
13579:
13580: if(equip == 0) {
13581: #ifdef SUPPORT_FPU
13582: equip |= (1 << 1); // 80x87 coprocessor installed
13583: #endif
13584: equip |= (1 << 2); // pointing device installed (PS/2)
13585: equip |= (2 << 4); // initial video mode (80x25 color)
13586: // equip |= (1 << 8); // 0 if DMA installed
13587: equip |= (2 << 9); // number of serial ports
13588: 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 13589:
13590: // check only A: and B: if it is floppy drive
13591: DWORD dwDrives = GetLogicalDrives();
13592: int n = 0;
13593: for(int i = 0; i < 2; i++) {
13594: if(dwDrives & (1 << i)) {
13595: char volume[] = "A:\\";
13596: volume[0] = 'A' + i;
13597: if(GetDriveType(volume) == DRIVE_REMOVABLE) {
13598: n++;
13599: }
13600: }
13601: }
13602: if(n != 0) {
13603: equip |= (1 << 0); // floppy disk(s) installed
13604: n--;
13605: equip |= (n << 6); // number of floppies installed less 1
13606: }
13607: // if(joyGetNumDevs() != 0) {
13608: // equip |= (1 << 12); // game port installed
13609: // }
1.1.1.26 root 13610: }
13611: return(equip);
13612: }
13613:
1.1 root 13614: void msdos_syscall(unsigned num)
13615: {
1.1.1.22 root 13616: #ifdef ENABLE_DEBUG_SYSCALL
13617: if(num == 0x68) {
13618: // dummy interrupt for EMS (int 67h)
1.1.1.33 root 13619: 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 13620: } else if(num == 0x69) {
13621: // dummy interrupt for XMS (call far)
1.1.1.33 root 13622: 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 13623: } else if(num == 0x6a) {
13624: // dummy interrupt for case map routine pointed in the country info
13625: } else {
1.1.1.33 root 13626: 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 13627: }
13628: #endif
1.1.1.36! root 13629: // update cursor position
! 13630: if(cursor_moved) {
! 13631: pcbios_update_cursor_position();
! 13632: cursor_moved = false;
! 13633: }
1.1.1.33 root 13634: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
1.1.1.22 root 13635:
1.1 root 13636: switch(num) {
13637: case 0x00:
1.1.1.28 root 13638: try {
13639: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13640: error("division by zero\n");
13641: } catch(...) {
13642: fatalerror("division by zero detected, and failed to terminate current process\n");
13643: }
1.1 root 13644: break;
13645: case 0x04:
1.1.1.28 root 13646: try {
13647: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13648: error("overflow\n");
13649: } catch(...) {
13650: fatalerror("overflow detected, and failed to terminate current process\n");
13651: }
1.1 root 13652: break;
13653: case 0x06:
13654: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 13655: if(!ignore_illegal_insn) {
1.1.1.28 root 13656: try {
13657: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13658: error("illegal instruction\n");
13659: } catch(...) {
13660: fatalerror("illegal instruction detected, and failed to terminate current process\n");
13661: }
1.1.1.14 root 13662: } else {
13663: #if defined(HAS_I386)
13664: m_eip++;
13665: #else
13666: m_pc++;
13667: #endif
13668: }
1.1 root 13669: break;
1.1.1.33 root 13670: case 0x09:
13671: // ctrl-break is pressed
13672: if(raise_int_1bh) {
13673: #if defined(HAS_I386)
13674: m_ext = 0; // not an external interrupt
13675: i386_trap(0x1b, 1, 0);
13676: m_ext = 1;
13677: #else
13678: PREFIX86(_interrupt)(0x1b);
13679: #endif
13680: raise_int_1bh = false;
13681: }
1.1.1.8 root 13682: case 0x08:
1.1.1.14 root 13683: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 13684: case 0x0b:
13685: case 0x0c:
13686: case 0x0d:
13687: case 0x0e:
13688: case 0x0f:
13689: // EOI
13690: pic[0].isr &= ~(1 << (num - 0x08));
13691: pic_update();
13692: break;
1.1 root 13693: case 0x10:
13694: // PC BIOS - Video
1.1.1.14 root 13695: if(!restore_console_on_exit) {
1.1.1.15 root 13696: change_console_size(scr_width, scr_height);
1.1 root 13697: }
1.1.1.3 root 13698: m_CF = 0;
1.1 root 13699: switch(REG8(AH)) {
1.1.1.16 root 13700: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 13701: case 0x01: pcbios_int_10h_01h(); break;
13702: case 0x02: pcbios_int_10h_02h(); break;
13703: case 0x03: pcbios_int_10h_03h(); break;
13704: case 0x05: pcbios_int_10h_05h(); break;
13705: case 0x06: pcbios_int_10h_06h(); break;
13706: case 0x07: pcbios_int_10h_07h(); break;
13707: case 0x08: pcbios_int_10h_08h(); break;
13708: case 0x09: pcbios_int_10h_09h(); break;
13709: case 0x0a: pcbios_int_10h_0ah(); break;
13710: case 0x0b: break;
13711: case 0x0c: break;
13712: case 0x0d: break;
13713: case 0x0e: pcbios_int_10h_0eh(); break;
13714: case 0x0f: pcbios_int_10h_0fh(); break;
13715: case 0x10: break;
1.1.1.14 root 13716: case 0x11: pcbios_int_10h_11h(); break;
13717: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 13718: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 13719: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 13720: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 13721: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
13722: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 13723: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 13724: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
13725: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 13726: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 13727: case 0x6f: break;
1.1.1.22 root 13728: case 0x80: m_CF = 1; break; // unknown
13729: case 0x81: m_CF = 1; break; // unknown
1.1 root 13730: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 13731: case 0x83: pcbios_int_10h_83h(); break;
13732: case 0x8b: break;
13733: case 0x8c: m_CF = 1; break; // unknown
13734: case 0x8d: m_CF = 1; break; // unknown
13735: case 0x8e: m_CF = 1; break; // unknown
13736: case 0x90: pcbios_int_10h_90h(); break;
13737: case 0x91: pcbios_int_10h_91h(); break;
13738: case 0x92: break;
13739: case 0x93: break;
13740: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 13741: case 0xfa: break; // ega register interface library is not installed
1.1 root 13742: case 0xfe: pcbios_int_10h_feh(); break;
13743: case 0xff: pcbios_int_10h_ffh(); break;
13744: default:
1.1.1.22 root 13745: 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));
13746: m_CF = 1;
1.1 root 13747: break;
13748: }
13749: break;
13750: case 0x11:
13751: // PC BIOS - Get Equipment List
1.1.1.26 root 13752: REG16(AX) = msdos_get_equipment();
1.1 root 13753: break;
13754: case 0x12:
13755: // PC BIOS - Get Memory Size
1.1.1.33 root 13756: REG16(AX) = *(UINT16 *)(mem + 0x413);
1.1 root 13757: break;
13758: case 0x13:
13759: // PC BIOS - Disk
1.1.1.22 root 13760: // 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 13761: REG8(AH) = 0xff;
1.1.1.3 root 13762: m_CF = 1;
1.1 root 13763: break;
13764: case 0x14:
13765: // PC BIOS - Serial I/O
1.1.1.25 root 13766: switch(REG8(AH)) {
13767: case 0x00: pcbios_int_14h_00h(); break;
13768: case 0x01: pcbios_int_14h_01h(); break;
13769: case 0x02: pcbios_int_14h_02h(); break;
13770: case 0x03: pcbios_int_14h_03h(); break;
13771: case 0x04: pcbios_int_14h_04h(); break;
13772: case 0x05: pcbios_int_14h_05h(); break;
13773: default:
13774: 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));
13775: break;
13776: }
1.1 root 13777: break;
13778: case 0x15:
13779: // PC BIOS
1.1.1.3 root 13780: m_CF = 0;
1.1 root 13781: switch(REG8(AH)) {
1.1.1.14 root 13782: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 13783: case 0x23: pcbios_int_15h_23h(); break;
13784: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 13785: case 0x41: break;
1.1 root 13786: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 13787: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 13788: case 0x53: pcbios_int_15h_53h(); break;
1.1 root 13789: case 0x86: pcbios_int_15h_86h(); break;
13790: case 0x87: pcbios_int_15h_87h(); break;
13791: case 0x88: pcbios_int_15h_88h(); break;
13792: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 13793: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 13794: case 0xc0: // PS/2 ???
13795: case 0xc1:
13796: case 0xc2:
1.1.1.30 root 13797: case 0xc3: // PS50+ ???
13798: case 0xc4:
1.1.1.22 root 13799: REG8(AH) = 0x86;
13800: m_CF = 1;
13801: break;
1.1.1.3 root 13802: #if defined(HAS_I386)
1.1 root 13803: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 13804: #endif
1.1 root 13805: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 13806: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 13807: default:
1.1.1.22 root 13808: 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));
13809: REG8(AH) = 0x86;
1.1.1.3 root 13810: m_CF = 1;
1.1 root 13811: break;
13812: }
13813: break;
13814: case 0x16:
13815: // PC BIOS - Keyboard
1.1.1.3 root 13816: m_CF = 0;
1.1 root 13817: switch(REG8(AH)) {
13818: case 0x00: pcbios_int_16h_00h(); break;
13819: case 0x01: pcbios_int_16h_01h(); break;
13820: case 0x02: pcbios_int_16h_02h(); break;
13821: case 0x03: pcbios_int_16h_03h(); break;
13822: case 0x05: pcbios_int_16h_05h(); break;
13823: case 0x10: pcbios_int_16h_00h(); break;
13824: case 0x11: pcbios_int_16h_01h(); break;
13825: case 0x12: pcbios_int_16h_12h(); break;
13826: case 0x13: pcbios_int_16h_13h(); break;
13827: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 13828: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 13829: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 13830: case 0xda: break; // unknown
13831: case 0xff: break; // unknown
1.1 root 13832: default:
1.1.1.22 root 13833: 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 13834: break;
13835: }
13836: break;
13837: case 0x17:
13838: // PC BIOS - Printer
1.1.1.22 root 13839: // 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 13840: break;
13841: case 0x1a:
13842: // PC BIOS - Timer
1.1.1.3 root 13843: m_CF = 0;
1.1 root 13844: switch(REG8(AH)) {
13845: case 0x00: pcbios_int_1ah_00h(); break;
13846: case 0x01: break;
13847: case 0x02: pcbios_int_1ah_02h(); break;
13848: case 0x03: break;
13849: case 0x04: pcbios_int_1ah_04h(); break;
13850: case 0x05: break;
13851: case 0x0a: pcbios_int_1ah_0ah(); break;
13852: case 0x0b: break;
1.1.1.14 root 13853: case 0x35: break; // Word Perfect Third Party Interface?
13854: case 0x36: break; // Word Perfect Third Party Interface
13855: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 13856: default:
1.1.1.22 root 13857: 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 13858: break;
13859: }
13860: break;
1.1.1.33 root 13861: case 0x1b:
13862: mem[0x471] = 0x00;
13863: break;
1.1 root 13864: case 0x20:
1.1.1.28 root 13865: try {
13866: msdos_process_terminate(SREG(CS), retval, 1);
13867: } catch(...) {
13868: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
13869: }
1.1 root 13870: break;
13871: case 0x21:
13872: // MS-DOS System Call
1.1.1.3 root 13873: m_CF = 0;
1.1.1.28 root 13874: try {
13875: switch(REG8(AH)) {
13876: case 0x00: msdos_int_21h_00h(); break;
13877: case 0x01: msdos_int_21h_01h(); break;
13878: case 0x02: msdos_int_21h_02h(); break;
13879: case 0x03: msdos_int_21h_03h(); break;
13880: case 0x04: msdos_int_21h_04h(); break;
13881: case 0x05: msdos_int_21h_05h(); break;
13882: case 0x06: msdos_int_21h_06h(); break;
13883: case 0x07: msdos_int_21h_07h(); break;
13884: case 0x08: msdos_int_21h_08h(); break;
13885: case 0x09: msdos_int_21h_09h(); break;
13886: case 0x0a: msdos_int_21h_0ah(); break;
13887: case 0x0b: msdos_int_21h_0bh(); break;
13888: case 0x0c: msdos_int_21h_0ch(); break;
13889: case 0x0d: msdos_int_21h_0dh(); break;
13890: case 0x0e: msdos_int_21h_0eh(); break;
13891: case 0x0f: msdos_int_21h_0fh(); break;
13892: case 0x10: msdos_int_21h_10h(); break;
13893: case 0x11: msdos_int_21h_11h(); break;
13894: case 0x12: msdos_int_21h_12h(); break;
13895: case 0x13: msdos_int_21h_13h(); break;
13896: case 0x14: msdos_int_21h_14h(); break;
13897: case 0x15: msdos_int_21h_15h(); break;
13898: case 0x16: msdos_int_21h_16h(); break;
13899: case 0x17: msdos_int_21h_17h(); break;
13900: case 0x18: msdos_int_21h_18h(); break;
13901: case 0x19: msdos_int_21h_19h(); break;
13902: case 0x1a: msdos_int_21h_1ah(); break;
13903: case 0x1b: msdos_int_21h_1bh(); break;
13904: case 0x1c: msdos_int_21h_1ch(); break;
13905: case 0x1d: msdos_int_21h_1dh(); break;
13906: case 0x1e: msdos_int_21h_1eh(); break;
13907: case 0x1f: msdos_int_21h_1fh(); break;
13908: case 0x20: msdos_int_21h_20h(); break;
13909: case 0x21: msdos_int_21h_21h(); break;
13910: case 0x22: msdos_int_21h_22h(); break;
13911: case 0x23: msdos_int_21h_23h(); break;
13912: case 0x24: msdos_int_21h_24h(); break;
13913: case 0x25: msdos_int_21h_25h(); break;
13914: case 0x26: msdos_int_21h_26h(); break;
13915: case 0x27: msdos_int_21h_27h(); break;
13916: case 0x28: msdos_int_21h_28h(); break;
13917: case 0x29: msdos_int_21h_29h(); break;
13918: case 0x2a: msdos_int_21h_2ah(); break;
13919: case 0x2b: msdos_int_21h_2bh(); break;
13920: case 0x2c: msdos_int_21h_2ch(); break;
13921: case 0x2d: msdos_int_21h_2dh(); break;
13922: case 0x2e: msdos_int_21h_2eh(); break;
13923: case 0x2f: msdos_int_21h_2fh(); break;
13924: case 0x30: msdos_int_21h_30h(); break;
13925: case 0x31: msdos_int_21h_31h(); break;
13926: case 0x32: msdos_int_21h_32h(); break;
13927: case 0x33: msdos_int_21h_33h(); break;
13928: case 0x34: msdos_int_21h_34h(); break;
13929: case 0x35: msdos_int_21h_35h(); break;
13930: case 0x36: msdos_int_21h_36h(); break;
13931: case 0x37: msdos_int_21h_37h(); break;
13932: case 0x38: msdos_int_21h_38h(); break;
13933: case 0x39: msdos_int_21h_39h(0); break;
13934: case 0x3a: msdos_int_21h_3ah(0); break;
13935: case 0x3b: msdos_int_21h_3bh(0); break;
13936: case 0x3c: msdos_int_21h_3ch(); break;
13937: case 0x3d: msdos_int_21h_3dh(); break;
13938: case 0x3e: msdos_int_21h_3eh(); break;
13939: case 0x3f: msdos_int_21h_3fh(); break;
13940: case 0x40: msdos_int_21h_40h(); break;
13941: case 0x41: msdos_int_21h_41h(0); break;
13942: case 0x42: msdos_int_21h_42h(); break;
13943: case 0x43: msdos_int_21h_43h(0); break;
13944: case 0x44: msdos_int_21h_44h(); break;
13945: case 0x45: msdos_int_21h_45h(); break;
13946: case 0x46: msdos_int_21h_46h(); break;
13947: case 0x47: msdos_int_21h_47h(0); break;
13948: case 0x48: msdos_int_21h_48h(); break;
13949: case 0x49: msdos_int_21h_49h(); break;
13950: case 0x4a: msdos_int_21h_4ah(); break;
13951: case 0x4b: msdos_int_21h_4bh(); break;
13952: case 0x4c: msdos_int_21h_4ch(); break;
13953: case 0x4d: msdos_int_21h_4dh(); break;
13954: case 0x4e: msdos_int_21h_4eh(); break;
13955: case 0x4f: msdos_int_21h_4fh(); break;
13956: case 0x50: msdos_int_21h_50h(); break;
13957: case 0x51: msdos_int_21h_51h(); break;
13958: case 0x52: msdos_int_21h_52h(); break;
1.1.1.33 root 13959: // 0x53: Translate BIOS Parameter Block to Drive Param Bock
1.1.1.28 root 13960: case 0x54: msdos_int_21h_54h(); break;
13961: case 0x55: msdos_int_21h_55h(); break;
13962: case 0x56: msdos_int_21h_56h(0); break;
13963: case 0x57: msdos_int_21h_57h(); break;
13964: case 0x58: msdos_int_21h_58h(); break;
13965: case 0x59: msdos_int_21h_59h(); break;
13966: case 0x5a: msdos_int_21h_5ah(); break;
13967: case 0x5b: msdos_int_21h_5bh(); break;
13968: case 0x5c: msdos_int_21h_5ch(); break;
13969: case 0x5d: msdos_int_21h_5dh(); break;
1.1.1.33 root 13970: // 0x5e: MS-Network
1.1.1.30 root 13971: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 13972: case 0x60: msdos_int_21h_60h(0); break;
13973: case 0x61: msdos_int_21h_61h(); break;
13974: case 0x62: msdos_int_21h_62h(); break;
13975: case 0x63: msdos_int_21h_63h(); break;
1.1.1.33 root 13976: // 0x64: Set Device Driver Lockahead Flag
1.1.1.28 root 13977: case 0x65: msdos_int_21h_65h(); break;
13978: case 0x66: msdos_int_21h_66h(); break;
13979: case 0x67: msdos_int_21h_67h(); break;
13980: case 0x68: msdos_int_21h_68h(); break;
13981: case 0x69: msdos_int_21h_69h(); break;
13982: case 0x6a: msdos_int_21h_6ah(); break;
13983: case 0x6b: msdos_int_21h_6bh(); break;
13984: case 0x6c: msdos_int_21h_6ch(0); break;
1.1.1.33 root 13985: // 0x6d: Find First ROM Program
13986: // 0x6e: Find Next ROM Program
13987: // 0x6f: Get/Set ROM Scan Start Address
13988: // 0x70: Windows95 - Get/Set Internationalization Information
1.1.1.28 root 13989: case 0x71:
1.1.1.33 root 13990: // Windows95 - Long Filename Functions
1.1.1.28 root 13991: switch(REG8(AL)) {
13992: case 0x0d: msdos_int_21h_710dh(); break;
13993: case 0x39: msdos_int_21h_39h(1); break;
13994: case 0x3a: msdos_int_21h_3ah(1); break;
13995: case 0x3b: msdos_int_21h_3bh(1); break;
13996: case 0x41: msdos_int_21h_7141h(1); break;
13997: case 0x43: msdos_int_21h_43h(1); break;
13998: case 0x47: msdos_int_21h_47h(1); break;
13999: case 0x4e: msdos_int_21h_714eh(); break;
14000: case 0x4f: msdos_int_21h_714fh(); break;
14001: case 0x56: msdos_int_21h_56h(1); break;
14002: case 0x60: msdos_int_21h_60h(1); break;
14003: case 0x6c: msdos_int_21h_6ch(1); break;
14004: case 0xa0: msdos_int_21h_71a0h(); break;
14005: case 0xa1: msdos_int_21h_71a1h(); break;
14006: case 0xa6: msdos_int_21h_71a6h(); break;
14007: case 0xa7: msdos_int_21h_71a7h(); break;
14008: case 0xa8: msdos_int_21h_71a8h(); break;
1.1.1.33 root 14009: // 0xa9: Server Create/Open File
1.1.1.28 root 14010: case 0xaa: msdos_int_21h_71aah(); break;
14011: default:
14012: 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));
14013: REG16(AX) = 0x7100;
14014: m_CF = 1;
14015: break;
14016: }
14017: break;
14018: // 0x72: Windows95 beta - LFN FindClose
14019: case 0x73:
1.1.1.33 root 14020: // Windows95 - FAT32 Functions
1.1.1.28 root 14021: switch(REG8(AL)) {
14022: case 0x00: msdos_int_21h_7300h(); break;
1.1.1.33 root 14023: // 0x01: Set Drive Locking ???
1.1.1.28 root 14024: case 0x02: msdos_int_21h_7302h(); break;
14025: case 0x03: msdos_int_21h_7303h(); break;
1.1.1.33 root 14026: // 0x04: Set DPB to Use for Formatting
14027: // 0x05: Extended Absolute Disk Read/Write
1.1.1.28 root 14028: default:
14029: 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));
14030: REG16(AX) = 0x7300;
14031: m_CF = 1;
14032: break;
14033: }
1.1 root 14034: break;
1.1.1.30 root 14035: case 0xdb: msdos_int_21h_dbh(); break;
14036: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 14037: default:
1.1.1.22 root 14038: 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 14039: REG16(AX) = 0x01;
1.1.1.3 root 14040: m_CF = 1;
1.1 root 14041: break;
14042: }
1.1.1.28 root 14043: } catch(int error) {
14044: REG16(AX) = error;
14045: m_CF = 1;
14046: } catch(...) {
14047: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 14048: m_CF = 1;
1.1 root 14049: }
1.1.1.3 root 14050: if(m_CF) {
1.1.1.23 root 14051: sda_t *sda = (sda_t *)(mem + SDA_TOP);
14052: sda->extended_error_code = REG16(AX);
14053: switch(sda->extended_error_code) {
14054: case 4: // Too many open files
14055: case 8: // Insufficient memory
14056: sda->error_class = 1; // Out of resource
14057: break;
14058: case 5: // Access denied
14059: sda->error_class = 3; // Authorization
14060: break;
14061: case 7: // Memory control block destroyed
14062: sda->error_class = 4; // Internal
14063: break;
14064: case 2: // File not found
14065: case 3: // Path not found
14066: case 15: // Invaid drive specified
14067: case 18: // No more files
14068: sda->error_class = 8; // Not found
14069: break;
14070: case 32: // Sharing violation
14071: case 33: // Lock violation
14072: sda->error_class = 10; // Locked
14073: break;
14074: // case 16: // Removal of current directory attempted
14075: case 19: // Attempted write on protected disk
14076: case 21: // Drive not ready
14077: // case 29: // Write failure
14078: // case 30: // Read failure
14079: // case 82: // Cannot create subdirectory
14080: sda->error_class = 11; // Media
14081: break;
14082: case 80: // File already exists
14083: sda->error_class = 12; // Already exist
14084: break;
14085: default:
14086: sda->error_class = 13; // Unknown
14087: break;
14088: }
14089: sda->suggested_action = 1; // Retry
14090: sda->locus_of_last_error = 1; // Unknown
1.1 root 14091: }
1.1.1.33 root 14092: if(ctrl_break_checking && ctrl_break_detected) {
1.1.1.26 root 14093: // raise int 23h
14094: #if defined(HAS_I386)
14095: m_ext = 0; // not an external interrupt
14096: i386_trap(0x23, 1, 0);
14097: m_ext = 1;
14098: #else
14099: PREFIX86(_interrupt)(0x23);
14100: #endif
14101: }
1.1 root 14102: break;
14103: case 0x22:
14104: fatalerror("int 22h (terminate address)\n");
14105: case 0x23:
1.1.1.28 root 14106: try {
14107: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
14108: } catch(...) {
14109: fatalerror("failed to terminate the current process by int 23h\n");
14110: }
1.1 root 14111: break;
14112: case 0x24:
1.1.1.32 root 14113: /*
1.1.1.28 root 14114: try {
14115: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
14116: } catch(...) {
14117: fatalerror("failed to terminate the current process by int 24h\n");
14118: }
1.1.1.32 root 14119: */
14120: msdos_int_24h();
1.1 root 14121: break;
14122: case 0x25:
14123: msdos_int_25h();
14124: break;
14125: case 0x26:
14126: msdos_int_26h();
14127: break;
14128: case 0x27:
1.1.1.28 root 14129: try {
14130: msdos_int_27h();
14131: } catch(...) {
14132: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
14133: }
1.1 root 14134: break;
14135: case 0x28:
14136: Sleep(10);
1.1.1.35 root 14137: REQUEST_HARDWRE_UPDATE();
1.1 root 14138: break;
14139: case 0x29:
14140: msdos_int_29h();
14141: break;
14142: case 0x2e:
14143: msdos_int_2eh();
14144: break;
14145: case 0x2f:
14146: // multiplex interrupt
14147: switch(REG8(AH)) {
1.1.1.22 root 14148: case 0x05: msdos_int_2fh_05h(); break;
14149: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 14150: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 14151: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 14152: case 0x14: msdos_int_2fh_14h(); break;
14153: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 14154: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 14155: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 14156: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 14157: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 14158: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 14159: case 0x46: msdos_int_2fh_46h(); break;
14160: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 14161: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 14162: case 0x4b: msdos_int_2fh_4bh(); break;
1.1 root 14163: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 14164: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.24 root 14165: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 14166: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.34 root 14167: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.30 root 14168: // Installation Check
14169: case 0x01: // PRINT.COM
14170: case 0x02: // PC LAN Program Redirector
14171: case 0x06: // ASSIGN
14172: case 0x08: // DRIVER.SYS
14173: case 0x10: // SHARE
14174: case 0x17: // Clibboard functions
14175: case 0x1b: // XMA2EMS.SYS
14176: case 0x23: // DR DOS 5.0 GRAFTABL
14177: case 0x27: // DR-DOR 6.0 TaskMAX
14178: case 0x2e: // Novell DOS 7 GRAFTABL
1.1.1.33 root 14179: case 0x39: // Kingswood TSR INTERFACE
14180: case 0x41: // DOS Enhanced LAN Manager 2.0+ MINIPOP/NETPOPUP
1.1.1.30 root 14181: case 0x45: // PROF.COM
14182: case 0x51: // ODIHELP.EXE
1.1.1.33 root 14183: case 0x52: // JAM.SYS v1.10+
1.1.1.30 root 14184: case 0x54: // POWER.EXE
14185: case 0x56: // INTERLNK
1.1.1.33 root 14186: case 0x57: // IOMEGA DRIVERS
1.1.1.30 root 14187: case 0x70: // License Service API
1.1.1.33 root 14188: case 0x72: // SRDISK v1.30+
1.1.1.30 root 14189: case 0x7a: // Novell NetWare
1.1.1.33 root 14190: case 0x7f: // PRINDIR v9.0
14191: case 0x80: // FAX BIOS
14192: case 0x81: // Nanosoft, Inc. TurboNET redirector
14193: case 0x82: // Nanosoft, Inc. CAPDOS
14194: case 0x89: // WHOA!.COM
14195: case 0x90: // Resident AID
1.1.1.30 root 14196: case 0x94: // MICRO.EXE
1.1.1.33 root 14197: case 0x97: // Micro Focus COBOL v3.1.31
14198: case 0x98: // Micro Focus COBOL v3.1.31
14199: case 0x99: // DOS Navigator II
14200: case 0x9e: // INTMON v2.1
14201: case 0x9f: // INTCFG v2.1
14202: case 0xa9: // METZTSR.COM
14203: case 0xab: // SRSoft MODAL PC v2
1.1.1.30 root 14204: case 0xac: // GRAPHICS.COM
1.1.1.33 root 14205: case 0xaf: // WinDOS v2.11
1.1.1.30 root 14206: case 0xb0: // GRAFTABLE.COM
1.1.1.33 root 14207: case 0xb4: // IBM PC3270 EMULATION PROG v3
1.1.1.30 root 14208: case 0xb8: // NETWORK
14209: case 0xb9: // RECEIVER.COM
14210: case 0xbc: // EGA.SYS
1.1.1.33 root 14211: case 0xbe: // REDVIEW
1.1.1.30 root 14212: case 0xbf: // PC LAN Program - REDIRIFS.EXE
14213: case 0xc0: // Novell LSL.COM
1.1.1.33 root 14214: case 0xc1: // Personal NetWare - STPIPX v1.00
14215: case 0xc3: // SETWPR.COM
14216: case 0xc5: // PC-DOS Econet v1.05
14217: case 0xc7: // COLAP.COM
14218: case 0xc9: // ThunderByte???
14219: case 0xca: // TBSCANX
14220: case 0xcb: // Communicating Applications Specification
14221: case 0xcc: // Tsoft NFSDRVR
14222: case 0xcd: // SWELL.EXE
14223: case 0xcf: // TEMPLEXX 1.0
14224: case 0xd0: // Lotus CD/Networker
1.1.1.30 root 14225: case 0xd2: // PCL-838.EXE
1.1.1.33 root 14226: case 0xd3: // TeleReplica
14227: case 0xd6: // VEDIT VSWAP
14228: case 0xd7: // Banyan VINES v4+
1.1.1.30 root 14229: case 0xd8: // Novell NetWare Lite - CLIENT.EXE
1.1.1.33 root 14230: case 0xda: // ZyXEL ZFAX v1.x
14231: case 0xdb: // ZyXEL ZFAX v2+
14232: case 0xdc: // GOLD.COM
14233: case 0xdd: // MIXFIX.EXE
14234: case 0xde: // Novell Netware - RPRINTER, NPRINTER
14235: case 0xdf: // HyperWare programs
14236: case 0xe0: // SETDRVER.COM v2.10+
14237: case 0xe1: // Phantom2 v1.1+
14238: case 0xe3: // ANARKEY.COM
14239: case 0xed: // Phar Lap DOS EXTENDERS
14240: case 0xee: // XVIEW
14241: case 0xf0: // 4MAP
14242: case 0xf1: // DOS EXTENDER
14243: case 0xf2: // WINX
14244: case 0xf4: // FINDIRQ.COM
14245: case 0xf7: // AUTOPARK.COM
14246: case 0xf8: // SuperStor PRO 2XON.COM
14247: case 0xfb: // AutoBraille v1.1A
14248: case 0xfe: // PC-NFS ???
14249: case 0xff: // Topware Network Operating System
1.1.1.30 root 14250: switch(REG8(AL)) {
14251: case 0x00:
14252: // This is not installed
14253: // REG8(AL) = 0x00;
14254: break;
1.1.1.33 root 14255: case 0x01:
14256: // Banyan VINES v4+ is not installed
14257: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
14258: break;
14259: }
1.1.1.30 root 14260: default:
14261: 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));
14262: REG16(AX) = 0x01;
14263: m_CF = 1;
14264: break;
14265: }
14266: break;
1.1.1.22 root 14267: default:
14268: 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));
14269: break;
1.1 root 14270: }
14271: break;
1.1.1.24 root 14272: case 0x33:
14273: switch(REG8(AH)) {
14274: case 0x00:
14275: // Mouse
14276: switch(REG8(AL)) {
14277: case 0x00: msdos_int_33h_0000h(); break;
14278: case 0x01: msdos_int_33h_0001h(); break;
14279: case 0x02: msdos_int_33h_0002h(); break;
14280: case 0x03: msdos_int_33h_0003h(); break;
1.1.1.34 root 14281: case 0x04: msdos_int_33h_0004h(); break;
1.1.1.24 root 14282: case 0x05: msdos_int_33h_0005h(); break;
14283: case 0x06: msdos_int_33h_0006h(); break;
14284: case 0x07: msdos_int_33h_0007h(); break;
14285: case 0x08: msdos_int_33h_0008h(); break;
14286: case 0x09: msdos_int_33h_0009h(); break;
1.1.1.34 root 14287: case 0x0a: break; // Define Text Cursor
1.1.1.24 root 14288: case 0x0b: msdos_int_33h_000bh(); break;
14289: case 0x0c: msdos_int_33h_000ch(); break;
1.1.1.34 root 14290: case 0x0d: break; // Light Pen Emulation On
14291: case 0x0e: break; // Light Pen Emulation Off
1.1.1.24 root 14292: case 0x0f: msdos_int_33h_000fh(); break;
1.1.1.34 root 14293: case 0x10: break; // Define Screen Region for Updating
1.1.1.24 root 14294: case 0x11: msdos_int_33h_0011h(); break;
1.1.1.34 root 14295: case 0x12: REG16(AX) = 0xffff; break; // Set Large Graphics Cursor Block
14296: case 0x13: break; // Define Double-Speed Threshold
1.1.1.24 root 14297: case 0x14: msdos_int_33h_0014h(); break;
14298: case 0x15: msdos_int_33h_0015h(); break;
14299: case 0x16: msdos_int_33h_0016h(); break;
14300: case 0x17: msdos_int_33h_0017h(); break;
14301: case 0x1a: msdos_int_33h_001ah(); break;
14302: case 0x1b: msdos_int_33h_001bh(); break;
14303: case 0x1d: msdos_int_33h_001dh(); break;
14304: case 0x1e: msdos_int_33h_001eh(); break;
1.1.1.34 root 14305: case 0x1f: msdos_int_33h_001fh(); break;
14306: case 0x20: msdos_int_33h_0020h(); break;
1.1.1.24 root 14307: case 0x21: msdos_int_33h_0021h(); break;
14308: case 0x22: msdos_int_33h_0022h(); break;
14309: case 0x23: msdos_int_33h_0023h(); break;
14310: case 0x24: msdos_int_33h_0024h(); break;
14311: case 0x26: msdos_int_33h_0026h(); break;
14312: case 0x2a: msdos_int_33h_002ah(); break;
1.1.1.34 root 14313: case 0x2f: break; // Mouse Hardware Reset
1.1.1.24 root 14314: case 0x31: msdos_int_33h_0031h(); break;
14315: case 0x32: msdos_int_33h_0032h(); break;
14316: default:
14317: 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));
14318: break;
14319: }
14320: break;
14321: default:
14322: 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));
14323: break;
14324: }
14325: break;
1.1.1.19 root 14326: case 0x68:
14327: // dummy interrupt for EMS (int 67h)
14328: switch(REG8(AH)) {
14329: case 0x40: msdos_int_67h_40h(); break;
14330: case 0x41: msdos_int_67h_41h(); break;
14331: case 0x42: msdos_int_67h_42h(); break;
14332: case 0x43: msdos_int_67h_43h(); break;
14333: case 0x44: msdos_int_67h_44h(); break;
14334: case 0x45: msdos_int_67h_45h(); break;
14335: case 0x46: msdos_int_67h_46h(); break;
14336: case 0x47: msdos_int_67h_47h(); break;
14337: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 14338: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
14339: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 14340: case 0x4b: msdos_int_67h_4bh(); break;
14341: case 0x4c: msdos_int_67h_4ch(); break;
14342: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 14343: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 14344: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 14345: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 14346: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 14347: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 14348: case 0x53: msdos_int_67h_53h(); break;
14349: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 14350: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
14351: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
14352: case 0x57: msdos_int_67h_57h(); break;
14353: case 0x58: msdos_int_67h_58h(); break;
14354: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
14355: case 0x5a: msdos_int_67h_5ah(); break;
14356: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
14357: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
14358: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.31 root 14359: // 0x60: EEMS - Get Physical Window Array
14360: // 0x61: EEMS - Generic Accelerator Card Support
14361: // 0x68: EEMS - Get Address of All Pge Frames om System
14362: // 0x69: EEMS - Map Page into Frame
14363: // 0x6a: EEMS - Page Mapping
14364: // 0xde: VCPI
1.1.1.30 root 14365: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 14366: default:
1.1.1.22 root 14367: 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 14368: REG8(AH) = 0x84;
14369: break;
14370: }
14371: break;
14372: #ifdef SUPPORT_XMS
14373: case 0x69:
14374: // dummy interrupt for XMS (call far)
1.1.1.28 root 14375: try {
14376: switch(REG8(AH)) {
14377: case 0x00: msdos_call_xms_00h(); break;
14378: case 0x01: msdos_call_xms_01h(); break;
14379: case 0x02: msdos_call_xms_02h(); break;
14380: case 0x03: msdos_call_xms_03h(); break;
14381: case 0x04: msdos_call_xms_04h(); break;
14382: case 0x05: msdos_call_xms_05h(); break;
14383: case 0x06: msdos_call_xms_06h(); break;
14384: case 0x07: msdos_call_xms_07h(); break;
14385: case 0x08: msdos_call_xms_08h(); break;
14386: case 0x09: msdos_call_xms_09h(); break;
14387: case 0x0a: msdos_call_xms_0ah(); break;
14388: case 0x0b: msdos_call_xms_0bh(); break;
14389: case 0x0c: msdos_call_xms_0ch(); break;
14390: case 0x0d: msdos_call_xms_0dh(); break;
14391: case 0x0e: msdos_call_xms_0eh(); break;
14392: case 0x0f: msdos_call_xms_0fh(); break;
14393: case 0x10: msdos_call_xms_10h(); break;
14394: case 0x11: msdos_call_xms_11h(); break;
14395: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 14396: #if defined(HAS_I386)
14397: case 0x88: msdos_call_xms_88h(); break;
14398: case 0x89: msdos_call_xms_89h(); break;
14399: case 0x8e: msdos_call_xms_8eh(); break;
14400: case 0x8f: msdos_call_xms_8fh(); break;
14401: #endif
1.1.1.28 root 14402: default:
14403: 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));
14404: REG16(AX) = 0x0000;
14405: REG8(BL) = 0x80; // function not implemented
14406: break;
14407: }
14408: } catch(...) {
1.1.1.19 root 14409: REG16(AX) = 0x0000;
1.1.1.28 root 14410: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 14411: }
14412: break;
14413: #endif
14414: case 0x6a:
1.1.1.24 root 14415: // irq12 (mouse)
14416: mouse_push_ax = REG16(AX);
14417: mouse_push_bx = REG16(BX);
14418: mouse_push_cx = REG16(CX);
14419: mouse_push_dx = REG16(DX);
14420: mouse_push_si = REG16(SI);
14421: mouse_push_di = REG16(DI);
14422:
1.1.1.34 root 14423: if(/*mouse.hidden == 0 && */mouse.call_addr.dw != 0) {
1.1.1.24 root 14424: REG16(AX) = mouse.status_irq;
14425: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 14426: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
14427: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
1.1.1.24 root 14428: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
14429: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
14430:
14431: mem[0xfffd0 + 0x02] = 0x9a; // call far
14432: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
14433: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
14434: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
14435: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
14436: } else {
14437: mem[0xfffd0 + 0x02] = 0x90; // nop
14438: mem[0xfffd0 + 0x03] = 0x90; // nop
14439: mem[0xfffd0 + 0x04] = 0x90; // nop
14440: mem[0xfffd0 + 0x05] = 0x90; // nop
14441: mem[0xfffd0 + 0x06] = 0x90; // nop
14442: }
14443: break;
14444: case 0x6b:
14445: // end of irq12 (mouse)
14446: REG16(AX) = mouse_push_ax;
14447: REG16(BX) = mouse_push_bx;
14448: REG16(CX) = mouse_push_cx;
14449: REG16(DX) = mouse_push_dx;
14450: REG16(SI) = mouse_push_si;
14451: REG16(DI) = mouse_push_di;
14452:
14453: // EOI
14454: if((pic[1].isr &= ~(1 << 4)) == 0) {
14455: pic[0].isr &= ~(1 << 2); // master
14456: }
14457: pic_update();
14458: break;
14459: case 0x6c:
1.1.1.19 root 14460: // dummy interrupt for case map routine pointed in the country info
14461: if(REG8(AL) >= 0x80) {
14462: char tmp[2] = {0};
14463: tmp[0] = REG8(AL);
14464: my_strupr(tmp);
14465: REG8(AL) = tmp[0];
14466: }
14467: break;
1.1.1.27 root 14468: case 0x6d:
14469: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
14470: REG8(AL) = 0x86; // not supported
14471: m_CF = 1;
14472: break;
1.1.1.32 root 14473: case 0x6e:
14474: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
14475: {
14476: UINT16 code = REG16(AX);
14477: if(code & 0xf0) {
14478: code = (code & 7) | ((code & 0x10) >> 1);
14479: }
14480: for(int i = 0; i < array_length(param_error_table); i++) {
14481: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
14482: const char *message = NULL;
14483: if(active_code_page == 932) {
14484: message = param_error_table[i].message_japanese;
14485: }
14486: if(message == NULL) {
14487: message = param_error_table[i].message_english;
14488: }
14489: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
14490: strcpy((char *)(mem + WORK_TOP + 1), message);
14491:
14492: SREG(ES) = WORK_TOP >> 4;
14493: i386_load_segment_descriptor(ES);
14494: REG16(DI) = 0x0000;
14495: break;
14496: }
14497: }
14498: }
14499: break;
1.1.1.8 root 14500: case 0x70:
14501: case 0x71:
14502: case 0x72:
14503: case 0x73:
14504: case 0x74:
14505: case 0x75:
14506: case 0x76:
14507: case 0x77:
14508: // EOI
14509: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
14510: pic[0].isr &= ~(1 << 2); // master
14511: }
14512: pic_update();
14513: break;
1.1 root 14514: default:
1.1.1.22 root 14515: // 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 14516: break;
14517: }
14518:
14519: // update cursor position
14520: if(cursor_moved) {
1.1.1.36! root 14521: pcbios_update_cursor_position();
1.1 root 14522: cursor_moved = false;
14523: }
14524: }
14525:
14526: // init
14527:
14528: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
14529: {
14530: // init file handler
14531: memset(file_handler, 0, sizeof(file_handler));
14532: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
14533: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
14534: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 14535: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 14536: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 14537: #else
14538: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
14539: #endif
14540: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 14541: }
1.1.1.21 root 14542: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 14543: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 14544: #else
14545: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 14546: #endif
1.1.1.21 root 14547: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
14548: }
1.1 root 14549: _dup2(0, DUP_STDIN);
14550: _dup2(1, DUP_STDOUT);
14551: _dup2(2, DUP_STDERR);
1.1.1.21 root 14552: _dup2(3, DUP_STDAUX);
14553: _dup2(4, DUP_STDPRN);
1.1 root 14554:
1.1.1.24 root 14555: // init mouse
14556: memset(&mouse, 0, sizeof(mouse));
1.1.1.34 root 14557: mouse.enabled = true; // from DOSBox
14558: mouse.hidden = 1; // hidden in default ???
14559: mouse.old_hidden = 1; // from DOSBox
14560: mouse.max_position.x = 8 * (scr_width - 1);
14561: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 14562: mouse.mickey.x = 8;
14563: mouse.mickey.y = 16;
14564:
1.1.1.26 root 14565: #ifdef SUPPORT_XMS
14566: // init xms
14567: msdos_xms_init();
14568: #endif
14569:
1.1 root 14570: // init process
14571: memset(process, 0, sizeof(process));
14572:
1.1.1.13 root 14573: // init dtainfo
14574: msdos_dta_info_init();
14575:
1.1 root 14576: // init memory
14577: memset(mem, 0, sizeof(mem));
14578:
14579: // bios data area
1.1.1.23 root 14580: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 14581: CONSOLE_SCREEN_BUFFER_INFO csbi;
14582: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 14583: CONSOLE_FONT_INFO cfi;
14584: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
14585:
14586: int regen = min(scr_width * scr_height * 2, 0x8000);
14587: text_vram_top_address = TEXT_VRAM_TOP;
14588: text_vram_end_address = text_vram_top_address + regen;
14589: shadow_buffer_top_address = SHADOW_BUF_TOP;
14590: shadow_buffer_end_address = shadow_buffer_top_address + regen;
14591:
14592: if(regen > 0x4000) {
14593: regen = 0x8000;
14594: vram_pages = 1;
14595: } else if(regen > 0x2000) {
14596: regen = 0x4000;
14597: vram_pages = 2;
14598: } else if(regen > 0x1000) {
14599: regen = 0x2000;
14600: vram_pages = 4;
14601: } else {
14602: regen = 0x1000;
14603: vram_pages = 8;
14604: }
1.1 root 14605:
1.1.1.25 root 14606: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
14607: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 14608: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
14609: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 14610: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.26 root 14611: // *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
1.1.1.25 root 14612: // *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32 root 14613: #ifdef EXT_BIOS_TOP
1.1.1.25 root 14614: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32 root 14615: #endif
1.1.1.26 root 14616: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1.1.33 root 14617: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
1.1 root 14618: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 14619: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
14620: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 14621: *(UINT16 *)(mem + 0x44e) = 0;
14622: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 14623: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 14624: *(UINT8 *)(mem + 0x460) = 7;
14625: *(UINT8 *)(mem + 0x461) = 7;
14626: *(UINT8 *)(mem + 0x462) = 0;
14627: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 14628: *(UINT8 *)(mem + 0x465) = 0x09;
14629: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 14630: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
14631: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
14632: *(UINT8 *)(mem + 0x487) = 0x60;
14633: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32 root 14634: #ifdef EXT_BIOS_TOP
1.1.1.25 root 14635: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32 root 14636: #endif
1.1.1.14 root 14637:
14638: // initial screen
14639: SMALL_RECT rect;
14640: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
14641: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
14642: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
14643: for(int x = 0; x < scr_width; x++) {
14644: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
14645: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
14646: }
14647: }
1.1 root 14648:
1.1.1.19 root 14649: // init mcb
1.1 root 14650: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 14651:
14652: // iret table
14653: // note: int 2eh vector should address the routine in command.com,
14654: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
14655: // so move iret table into allocated memory block
14656: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
1.1.1.33 root 14657: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, IRET_SIZE >> 4);
1.1.1.19 root 14658: IRET_TOP = seg << 4;
14659: seg += IRET_SIZE >> 4;
1.1.1.25 root 14660: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 14661:
14662: // dummy xms/ems device
1.1.1.33 root 14663: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
1.1.1.19 root 14664: XMS_TOP = seg << 4;
14665: seg += XMS_SIZE >> 4;
14666:
14667: // environment
1.1.1.33 root 14668: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
1.1 root 14669: int env_seg = seg;
14670: int ofs = 0;
1.1.1.32 root 14671: char env_append[ENV_SIZE] = {0}, append_added = 0;
14672: char comspec_added = 0;
1.1.1.33 root 14673: char lastdrive_added = 0;
1.1.1.32 root 14674: char env_msdos_path[ENV_SIZE] = {0};
14675: char env_path[ENV_SIZE] = {0}, path_added = 0;
1.1.1.33 root 14676: char prompt_added = 0;
1.1.1.32 root 14677: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
1.1.1.33 root 14678: char tz_added = 0;
1.1.1.32 root 14679: char *path, *short_path;
14680:
14681: if((path = getenv("MSDOS_APPEND")) != NULL) {
14682: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14683: strcpy(env_append, short_path);
14684: }
14685: }
14686: if((path = getenv("APPEND")) != NULL) {
14687: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14688: if(env_append[0] != '\0') {
14689: strcat(env_append, ";");
14690: }
14691: strcat(env_append, short_path);
14692: }
14693: }
14694:
14695: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
14696: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14697: strcpy(comspec_path, short_path);
14698: }
14699: }
14700: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
14701: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14702: strcpy(comspec_path, short_path);
14703: }
14704: }
1.1 root 14705:
1.1.1.28 root 14706: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32 root 14707: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14708: strcpy(env_msdos_path, short_path);
14709: strcpy(env_path, short_path);
1.1.1.14 root 14710: }
14711: }
1.1.1.28 root 14712: if((path = getenv("PATH")) != NULL) {
1.1.1.32 root 14713: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14714: if(env_path[0] != '\0') {
14715: strcat(env_path, ";");
14716: }
14717: strcat(env_path, short_path);
1.1.1.9 root 14718: }
14719: }
1.1.1.32 root 14720:
14721: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
14722: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 14723: }
1.1.1.32 root 14724: for(int i = 0; i < 4; i++) {
14725: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
14726: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
14727: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14728: strcpy(env_temp, short_path);
14729: break;
14730: }
14731: }
1.1.1.24 root 14732: }
1.1.1.32 root 14733:
1.1.1.9 root 14734: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 14735: // lower to upper
1.1.1.28 root 14736: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 14737: strcpy(tmp, *p);
14738: for(int i = 0;; i++) {
14739: if(tmp[i] == '=') {
14740: tmp[i] = '\0';
14741: sprintf(name, ";%s;", tmp);
1.1.1.25 root 14742: my_strupr(name);
1.1 root 14743: tmp[i] = '=';
14744: break;
14745: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 14746: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 14747: }
14748: }
1.1.1.33 root 14749: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
14750: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
14751: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 14752: // ignore non standard environments
14753: } else {
1.1.1.33 root 14754: if(strncmp(tmp, "APPEND=", 7) == 0) {
1.1.1.32 root 14755: if(env_append[0] != '\0') {
14756: sprintf(tmp, "APPEND=%s", env_append);
14757: } else {
14758: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
14759: }
14760: append_added = 1;
14761: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 14762: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32 root 14763: comspec_added = 1;
1.1.1.33 root 14764: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
14765: char *env = getenv("MSDOS_LASTDRIVE");
14766: if(env != NULL) {
14767: sprintf(tmp, "LASTDRIVE=%s", env);
14768: }
14769: lastdrive_added = 1;
14770: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
1.1.1.28 root 14771: if(env_msdos_path[0] != '\0') {
14772: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
14773: } else {
14774: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
14775: }
1.1.1.33 root 14776: } else if(strncmp(tmp, "PATH=", 5) == 0) {
1.1.1.28 root 14777: if(env_path[0] != '\0') {
14778: sprintf(tmp, "PATH=%s", env_path);
14779: } else {
14780: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
14781: }
1.1.1.32 root 14782: path_added = 1;
1.1.1.33 root 14783: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
14784: prompt_added = 1;
1.1.1.28 root 14785: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
14786: if(env_temp[0] != '\0') {
14787: sprintf(tmp, "TEMP=%s", env_temp);
14788: } else {
14789: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
14790: }
1.1.1.32 root 14791: temp_added = 1;
1.1.1.33 root 14792: } else if(strncmp(tmp, "TMP=", 4) == 0) {
1.1.1.28 root 14793: if(env_temp[0] != '\0') {
14794: sprintf(tmp, "TMP=%s", env_temp);
14795: } else {
14796: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 14797: }
1.1.1.32 root 14798: tmp_added = 1;
1.1.1.33 root 14799: } else if(strncmp(tmp, "TZ=", 3) == 0) {
14800: char *env = getenv("MSDOS_TZ");
14801: if(env != NULL) {
14802: sprintf(tmp, "TZ=%s", env);
14803: }
14804: tz_added = 1;
1.1 root 14805: }
14806: int len = strlen(tmp);
1.1.1.14 root 14807: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 14808: fatalerror("too many environments\n");
14809: }
14810: memcpy(mem + (seg << 4) + ofs, tmp, len);
14811: ofs += len + 1;
14812: }
14813: }
1.1.1.32 root 14814: if(!append_added && env_append[0] != '\0') {
14815: #define SET_ENV(name, value) { \
14816: char tmp[ENV_SIZE]; \
14817: sprintf(tmp, "%s=%s", name, value); \
14818: int len = strlen(tmp); \
14819: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
14820: fatalerror("too many environments\n"); \
14821: } \
14822: memcpy(mem + (seg << 4) + ofs, tmp, len); \
14823: ofs += len + 1; \
14824: }
14825: SET_ENV("APPEND", env_append);
14826: }
14827: if(!comspec_added) {
14828: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
14829: }
1.1.1.33 root 14830: if(!lastdrive_added) {
14831: SET_ENV("LASTDRIVE", "Z");
14832: }
1.1.1.32 root 14833: if(!path_added) {
14834: SET_ENV("PATH", env_path);
14835: }
1.1.1.33 root 14836: if(!prompt_added) {
14837: SET_ENV("PROMPT", "$P$G");
14838: }
1.1.1.32 root 14839: if(!temp_added) {
14840: SET_ENV("TEMP", env_temp);
14841: }
14842: if(!tmp_added) {
14843: SET_ENV("TMP", env_temp);
14844: }
1.1.1.33 root 14845: if(!tz_added) {
14846: TIME_ZONE_INFORMATION tzi;
14847: HKEY hKey, hSubKey;
14848: char tzi_std_name[64];
14849: char tz_std[8] = "GMT";
14850: char tz_dlt[8] = "GST";
14851: char tz_value[32];
14852:
14853: // timezone name from GetTimeZoneInformation may not be english
14854: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
14855: setlocale(LC_CTYPE, "");
14856: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
14857:
14858: // get english timezone name from registry
14859: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
14860: for(DWORD i = 0; !tz_added; i++) {
14861: char reg_name[256], sub_key[1024], std_name[256];
14862: DWORD size;
14863: FILETIME ftTime;
14864: LONG result = RegEnumKeyEx(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
14865:
14866: if(result == ERROR_SUCCESS) {
14867: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
14868: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
14869: if(RegQueryValueEx(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
14870: // search english timezone name from table
14871: if (strcmp(std_name, tzi_std_name) == 0) {
14872: for(int j = 0; j < array_length(tz_table); j++) {
14873: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
14874: if(tz_table[j].std != NULL) {
14875: strcpy(tz_std, tz_table[j].std);
14876: }
14877: if(tz_table[j].dlt != NULL) {
14878: strcpy(tz_dlt, tz_table[j].dlt);
14879: }
14880: tz_added = 1;
14881: break;
14882: }
14883: }
14884: }
14885: }
14886: RegCloseKey(hSubKey);
14887: }
14888: } else if(result == ERROR_NO_MORE_ITEMS) {
14889: break;
14890: }
14891: }
14892: RegCloseKey(hKey);
14893: }
14894: if((tzi.Bias % 60) != 0) {
14895: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
14896: } else {
14897: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
14898: }
14899: if(daylight) {
14900: strcat(tz_value, tz_dlt);
14901: }
14902: SET_ENV("TZ", tz_value);
14903: }
1.1 root 14904: seg += (ENV_SIZE >> 4);
14905:
14906: // psp
1.1.1.33 root 14907: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
1.1 root 14908: current_psp = seg;
1.1.1.35 root 14909: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
14910: psp->parent_psp = current_psp;
1.1 root 14911: seg += (PSP_SIZE >> 4);
14912:
1.1.1.19 root 14913: // first free mcb in conventional memory
1.1.1.33 root 14914: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 14915: first_mcb = seg;
14916:
1.1.1.19 root 14917: // dummy mcb to link to umb
1.1.1.33 root 14918: #if 0
14919: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4)); // link umb
14920: #else
14921: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0); // unlink umb
14922: #endif
1.1.1.19 root 14923:
14924: // first free mcb in upper memory block
1.1.1.8 root 14925: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 14926:
1.1.1.29 root 14927: #ifdef SUPPORT_HMA
14928: // first free mcb in high memory area
14929: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14930: #endif
14931:
1.1.1.26 root 14932: // interrupt vector
14933: for(int i = 0; i < 0x80; i++) {
14934: *(UINT16 *)(mem + 4 * i + 0) = i;
14935: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
14936: }
1.1.1.35 root 14937: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffd:0018 irq0 (system timer)
1.1.1.26 root 14938: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
14939: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
14940: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
14941: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
14942: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
14943: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
14944: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
14945:
1.1.1.29 root 14946: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 14947: static const struct {
14948: UINT16 attributes;
14949: char *dev_name;
14950: } dummy_devices[] = {
14951: {0x8013, "CON "},
14952: {0x8000, "AUX "},
14953: {0xa0c0, "PRN "},
14954: {0x8008, "CLOCK$ "},
14955: {0x8000, "COM1 "},
14956: {0xa0c0, "LPT1 "},
14957: {0xa0c0, "LPT2 "},
14958: {0xa0c0, "LPT3 "},
14959: {0x8000, "COM2 "},
14960: {0x8000, "COM3 "},
14961: {0x8000, "COM4 "},
1.1.1.30 root 14962: // {0xc000, "CONFIG$ "},
14963: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 14964: };
14965: static const UINT8 dummy_device_routine[] = {
14966: // from NUL device of Windows 98 SE
14967: // or word ptr ES:[BX+03],0100
14968: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
14969: // retf
14970: 0xcb,
14971: };
1.1.1.29 root 14972: device_t *last = NULL;
1.1.1.32 root 14973: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 14974: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 14975: device->next_driver.w.l = 22 + 18 * (i + 1);
14976: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 14977: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 14978: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
14979: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 14980: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 14981: last = device;
14982: }
14983: if(last != NULL) {
14984: last->next_driver.w.l = 0;
14985: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 14986: }
1.1.1.29 root 14987: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 14988:
1.1.1.25 root 14989: // dos info
14990: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
14991: dos_info->magic_word = 1;
14992: dos_info->first_mcb = MEMORY_TOP >> 4;
14993: dos_info->first_dpb.w.l = 0;
14994: dos_info->first_dpb.w.h = DPB_TOP >> 4;
14995: dos_info->first_sft.w.l = 0;
14996: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.26 root 14997: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 3rd device in IO.SYS
1.1.1.25 root 14998: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 14999: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 15000: dos_info->con_device.w.h = DEVICE_TOP >> 4;
15001: dos_info->max_sector_len = 512;
15002: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
15003: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
15004: dos_info->cds.w.l = 0;
15005: dos_info->cds.w.h = CDS_TOP >> 4;
15006: dos_info->fcb_table.w.l = 0;
15007: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
15008: dos_info->last_drive = 'Z' - 'A' + 1;
15009: dos_info->buffers_x = 20;
15010: dos_info->buffers_y = 0;
15011: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 15012: dos_info->nul_device.next_driver.w.l = 22;
15013: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 15014: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 15015: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
15016: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 15017: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
15018: dos_info->disk_buf_heads.w.l = 0;
15019: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
15020: dos_info->first_umb_fcb = UMB_TOP >> 4;
15021: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 15022: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 15023:
15024: char *env;
15025: if((env = getenv("LASTDRIVE")) != NULL) {
15026: if(env[0] >= 'A' && env[0] <= 'Z') {
15027: dos_info->last_drive = env[0] - 'A' + 1;
15028: } else if(env[0] >= 'a' && env[0] <= 'z') {
15029: dos_info->last_drive = env[0] - 'a' + 1;
15030: }
15031: }
15032: if((env = getenv("windir")) != NULL) {
15033: if(env[0] >= 'A' && env[0] <= 'Z') {
15034: dos_info->boot_drive = env[0] - 'A' + 1;
15035: } else if(env[0] >= 'a' && env[0] <= 'z') {
15036: dos_info->boot_drive = env[0] - 'a' + 1;
15037: }
15038: }
15039: #if defined(HAS_I386)
15040: dos_info->i386_or_later = 1;
15041: #else
15042: dos_info->i386_or_later = 0;
15043: #endif
15044: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
15045:
1.1.1.27 root 15046: // ems (int 67h) and xms
1.1.1.25 root 15047: device_t *xms_device = (device_t *)(mem + XMS_TOP);
15048: xms_device->next_driver.w.l = 0xffff;
15049: xms_device->next_driver.w.h = 0xffff;
15050: xms_device->attributes = 0xc000;
1.1.1.29 root 15051: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
15052: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 15053: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
15054:
1.1.1.26 root 15055: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
15056: mem[XMS_TOP + 0x13] = 0x68;
15057: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 15058: #ifdef SUPPORT_XMS
15059: if(support_xms) {
1.1.1.26 root 15060: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
15061: mem[XMS_TOP + 0x16] = 0x69;
15062: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 15063: } else
15064: #endif
1.1.1.26 root 15065: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 15066: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 15067:
1.1.1.26 root 15068: // irq12 routine (mouse)
1.1.1.24 root 15069: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
15070: mem[0xfffd0 + 0x01] = 0x6a;
15071: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
15072: mem[0xfffd0 + 0x03] = 0xff;
15073: mem[0xfffd0 + 0x04] = 0xff;
15074: mem[0xfffd0 + 0x05] = 0xff;
15075: mem[0xfffd0 + 0x06] = 0xff;
15076: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
15077: mem[0xfffd0 + 0x08] = 0x6b;
15078: mem[0xfffd0 + 0x09] = 0xcf; // iret
15079:
1.1.1.27 root 15080: // case map routine
15081: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
15082: mem[0xfffd0 + 0x0b] = 0x6c;
15083: mem[0xfffd0 + 0x0c] = 0xcb; // retf
15084:
15085: // font read routine
15086: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
15087: mem[0xfffd0 + 0x0e] = 0x6d;
15088: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 15089:
1.1.1.32 root 15090: // error message read routine
15091: mem[0xfffd0 + 0x10] = 0xcd; // int 6eh (dummy)
15092: mem[0xfffd0 + 0x11] = 0x6e;
15093: mem[0xfffd0 + 0x12] = 0xcb; // retf
15094:
1.1.1.35 root 15095: // dummy loop to wait BIOS/DOS service is done
15096: mem[0xfffd0 + 0x13] = 0xe6; // out f7h, al
15097: mem[0xfffd0 + 0x14] = 0xf7;
15098: mem[0xfffd0 + 0x15] = 0x78; // js/jns -4
15099: mem[0xfffd0 + 0x16] = 0xfc;
15100: mem[0xfffd0 + 0x17] = 0xcb; // retf
15101:
1.1.1.26 root 15102: // irq0 routine (system time)
1.1.1.35 root 15103: mem[0xfffd0 + 0x18] = 0xcd; // int 1ch
15104: mem[0xfffd0 + 0x19] = 0x1c;
15105: mem[0xfffd0 + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008
15106: mem[0xfffd0 + 0x1b] = 0x08;
15107: mem[0xfffd0 + 0x1c] = 0x00;
15108: mem[0xfffd0 + 0x1d] = ((IRET_TOP >> 4) ) & 0xff;
15109: mem[0xfffd0 + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 15110:
1.1.1.26 root 15111: // boot routine
1.1 root 15112: mem[0xffff0] = 0xf4; // halt
15113: mem[0xffff1] = 0xcd; // int 21h
15114: mem[0xffff2] = 0x21;
15115: mem[0xffff3] = 0xcb; // retf
15116:
1.1.1.24 root 15117: mem[0xffff5] = '0'; // rom date
15118: mem[0xffff6] = '2';
15119: mem[0xffff7] = '/';
15120: mem[0xffff8] = '2';
15121: mem[0xffff9] = '2';
15122: mem[0xffffa] = '/';
15123: mem[0xffffb] = '0';
15124: mem[0xffffc] = '6';
15125: mem[0xffffe] = 0xfc; // machine id
15126: mem[0xfffff] = 0x00;
15127:
1.1 root 15128: // param block
15129: // + 0: param block (22bytes)
15130: // +24: fcb1/2 (20bytes)
15131: // +44: command tail (128bytes)
15132: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
15133: param->env_seg = 0;
15134: param->cmd_line.w.l = 44;
15135: param->cmd_line.w.h = (WORK_TOP >> 4);
15136: param->fcb1.w.l = 24;
15137: param->fcb1.w.h = (WORK_TOP >> 4);
15138: param->fcb2.w.l = 24;
15139: param->fcb2.w.h = (WORK_TOP >> 4);
15140:
15141: memset(mem + WORK_TOP + 24, 0x20, 20);
15142:
15143: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
15144: if(argc > 1) {
15145: sprintf(cmd_line->cmd, " %s", argv[1]);
15146: for(int i = 2; i < argc; i++) {
15147: char tmp[128];
15148: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
15149: strcpy(cmd_line->cmd, tmp);
15150: }
15151: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
15152: } else {
15153: cmd_line->len = 0;
15154: }
15155: cmd_line->cmd[cmd_line->len] = 0x0d;
15156:
15157: // system file table
1.1.1.21 root 15158: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
15159: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 15160:
1.1.1.19 root 15161: // disk buffer header (from DOSBox)
15162: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
15163: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
15164: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
15165: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
15166: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
15167:
1.1 root 15168: // current directory structure
15169: msdos_cds_update(_getdrive() - 1);
15170:
15171: // fcb table
15172: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 15173: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 15174:
1.1.1.17 root 15175: // nls stuff
15176: msdos_nls_tables_init();
1.1 root 15177:
15178: // execute command
1.1.1.28 root 15179: try {
15180: if(msdos_process_exec(argv[0], param, 0)) {
15181: fatalerror("'%s' not found\n", argv[0]);
15182: }
15183: } catch(...) {
15184: // we should not reach here :-(
15185: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 15186: }
15187: retval = 0;
15188: return(0);
15189: }
15190:
15191: #define remove_std_file(path) { \
15192: int fd = _open(path, _O_RDONLY | _O_BINARY); \
15193: if(fd != -1) { \
15194: _lseek(fd, 0, SEEK_END); \
15195: int size = _tell(fd); \
15196: _close(fd); \
15197: if(size == 0) { \
15198: remove(path); \
15199: } \
15200: } \
15201: }
15202:
15203: void msdos_finish()
15204: {
15205: for(int i = 0; i < MAX_FILES; i++) {
15206: if(file_handler[i].valid) {
15207: _close(i);
15208: }
15209: }
1.1.1.21 root 15210: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 15211: remove_std_file("stdaux.txt");
1.1.1.21 root 15212: #endif
15213: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 15214: remove_std_file("stdprn.txt");
15215: #endif
1.1.1.30 root 15216: #ifdef SUPPORT_XMS
15217: msdos_xms_finish();
15218: #endif
1.1 root 15219: msdos_dbcs_table_finish();
15220: }
15221:
15222: /* ----------------------------------------------------------------------------
15223: PC/AT hardware emulation
15224: ---------------------------------------------------------------------------- */
15225:
15226: void hardware_init()
15227: {
1.1.1.3 root 15228: CPU_INIT_CALL(CPU_MODEL);
1.1 root 15229: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 15230: m_IF = 1;
1.1.1.3 root 15231: #if defined(HAS_I386)
1.1 root 15232: cpu_type = (REG32(EDX) >> 8) & 0x0f;
15233: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 15234: #endif
15235: i386_set_a20_line(0);
1.1.1.14 root 15236:
1.1.1.19 root 15237: ems_init();
1.1.1.25 root 15238: dma_init();
1.1 root 15239: pic_init();
1.1.1.25 root 15240: pio_init();
1.1.1.8 root 15241: #ifdef PIT_ALWAYS_RUNNING
15242: pit_init();
15243: #else
1.1 root 15244: pit_active = 0;
15245: #endif
1.1.1.25 root 15246: sio_init();
1.1.1.8 root 15247: cmos_init();
15248: kbd_init();
1.1 root 15249: }
15250:
1.1.1.10 root 15251: void hardware_finish()
15252: {
15253: #if defined(HAS_I386)
15254: vtlb_free(m_vtlb);
15255: #endif
1.1.1.19 root 15256: ems_finish();
1.1.1.25 root 15257: sio_finish();
1.1.1.10 root 15258: }
15259:
1.1.1.28 root 15260: void hardware_release()
15261: {
15262: // release hardware resources when this program will be terminated abnormally
15263: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 15264: if(fp_debug_log != NULL) {
15265: fclose(fp_debug_log);
15266: fp_debug_log = NULL;
1.1.1.28 root 15267: }
15268: #endif
15269: #if defined(HAS_I386)
15270: vtlb_free(m_vtlb);
15271: #endif
15272: ems_release();
15273: sio_release();
15274: }
15275:
1.1 root 15276: void hardware_run()
15277: {
1.1.1.22 root 15278: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 15279: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.33 root 15280: fp_debug_log = fopen("debug.log", "w");
1.1.1.22 root 15281: #endif
1.1.1.3 root 15282: while(!m_halted) {
15283: #if defined(HAS_I386)
1.1 root 15284: CPU_EXECUTE_CALL(i386);
1.1.1.14 root 15285: if(m_eip != m_prev_eip) {
1.1.1.35 root 15286: idle_ops++;
15287: }
1.1.1.14 root 15288: #else
1.1.1.35 root 15289: CPU_EXECUTE_CALL(CPU_MODEL);
1.1.1.14 root 15290: if(m_pc != m_prevpc) {
1.1.1.35 root 15291: idle_ops++;
1.1.1.14 root 15292: }
1.1.1.35 root 15293: #endif
15294: if(++update_ops == UPDATE_OPS) {
1.1 root 15295: hardware_update();
1.1.1.35 root 15296: update_ops = 0;
1.1 root 15297: }
15298: }
1.1.1.22 root 15299: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 15300: if(fp_debug_log != NULL) {
15301: fclose(fp_debug_log);
15302: fp_debug_log = NULL;
1.1.1.28 root 15303: }
1.1.1.22 root 15304: #endif
1.1 root 15305: }
15306:
15307: void hardware_update()
15308: {
1.1.1.8 root 15309: static UINT32 prev_time = 0;
15310: UINT32 cur_time = timeGetTime();
15311:
15312: if(prev_time != cur_time) {
15313: // update pit and raise irq0
15314: #ifndef PIT_ALWAYS_RUNNING
15315: if(pit_active)
15316: #endif
15317: {
15318: if(pit_run(0, cur_time)) {
15319: pic_req(0, 0, 1);
15320: }
15321: pit_run(1, cur_time);
15322: pit_run(2, cur_time);
15323: }
1.1.1.24 root 15324:
1.1.1.25 root 15325: // update sio and raise irq4/3
1.1.1.29 root 15326: for(int c = 0; c < 4; c++) {
1.1.1.25 root 15327: sio_update(c);
15328: }
15329:
1.1.1.24 root 15330: // update keyboard and mouse
1.1.1.14 root 15331: static UINT32 prev_tick = 0;
15332: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 15333:
1.1.1.14 root 15334: if(prev_tick != cur_tick) {
15335: // update keyboard flags
15336: UINT8 state;
1.1.1.24 root 15337: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
15338: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
15339: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
15340: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
15341: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
15342: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
15343: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
15344: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 15345: mem[0x417] = state;
15346: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
15347: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
15348: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
15349: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 15350: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
15351: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 15352: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
15353: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
15354: mem[0x418] = state;
15355:
1.1.1.24 root 15356: // update console input if needed
1.1.1.34 root 15357: if(!key_changed || mouse.hidden == 0) {
1.1.1.24 root 15358: update_console_input();
15359: }
15360:
15361: // raise irq1 if key is pressed/released
15362: if(key_changed) {
1.1.1.8 root 15363: pic_req(0, 1, 1);
1.1.1.24 root 15364: key_changed = false;
15365: }
15366:
15367: // raise irq12 if mouse status is changed
15368: if(mouse.status & mouse.call_mask) {
1.1.1.34 root 15369: // if(mouse.hidden == 0) {
1.1.1.24 root 15370: pic_req(1, 4, 1);
15371: mouse.status_irq = mouse.status & mouse.call_mask;
1.1.1.34 root 15372: // }
1.1.1.24 root 15373: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 15374: }
1.1.1.24 root 15375:
1.1.1.14 root 15376: prev_tick = cur_tick;
1.1.1.8 root 15377: }
1.1.1.24 root 15378:
1.1.1.19 root 15379: // update daily timer counter
15380: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 15381:
1.1.1.8 root 15382: prev_time = cur_time;
1.1 root 15383: }
15384: }
15385:
1.1.1.19 root 15386: // ems
15387:
15388: void ems_init()
15389: {
15390: memset(ems_handles, 0, sizeof(ems_handles));
15391: memset(ems_pages, 0, sizeof(ems_pages));
15392: free_ems_pages = MAX_EMS_PAGES;
15393: }
15394:
15395: void ems_finish()
15396: {
1.1.1.28 root 15397: ems_release();
15398: }
15399:
15400: void ems_release()
15401: {
1.1.1.31 root 15402: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 15403: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 15404: free(ems_handles[i].buffer);
15405: ems_handles[i].buffer = NULL;
15406: }
15407: }
15408: }
15409:
15410: void ems_allocate_pages(int handle, int pages)
15411: {
15412: if(pages > 0) {
15413: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
15414: } else {
15415: ems_handles[handle].buffer = NULL;
15416: }
15417: ems_handles[handle].pages = pages;
15418: ems_handles[handle].allocated = true;
15419: free_ems_pages -= pages;
15420: }
15421:
15422: void ems_reallocate_pages(int handle, int pages)
15423: {
15424: if(ems_handles[handle].allocated) {
15425: if(ems_handles[handle].pages != pages) {
15426: UINT8 *new_buffer = NULL;
15427:
15428: if(pages > 0) {
15429: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
15430: }
1.1.1.32 root 15431: if(ems_handles[handle].buffer != NULL) {
15432: if(new_buffer != NULL) {
1.1.1.19 root 15433: if(pages > ems_handles[handle].pages) {
15434: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
15435: } else {
15436: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
15437: }
15438: }
15439: free(ems_handles[handle].buffer);
15440: ems_handles[handle].buffer = NULL;
15441: }
15442: free_ems_pages += ems_handles[handle].pages;
15443:
15444: ems_handles[handle].buffer = new_buffer;
15445: ems_handles[handle].pages = pages;
15446: free_ems_pages -= pages;
15447: }
15448: } else {
15449: ems_allocate_pages(handle, pages);
15450: }
15451: }
15452:
15453: void ems_release_pages(int handle)
15454: {
15455: if(ems_handles[handle].allocated) {
1.1.1.32 root 15456: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 15457: free(ems_handles[handle].buffer);
15458: ems_handles[handle].buffer = NULL;
15459: }
15460: free_ems_pages += ems_handles[handle].pages;
15461: ems_handles[handle].allocated = false;
15462: }
15463: }
15464:
15465: void ems_map_page(int physical, int handle, int logical)
15466: {
15467: if(ems_pages[physical].mapped) {
15468: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
15469: return;
15470: }
15471: ems_unmap_page(physical);
15472: }
1.1.1.32 root 15473: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 15474: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
15475: }
15476: ems_pages[physical].handle = handle;
15477: ems_pages[physical].page = logical;
15478: ems_pages[physical].mapped = true;
15479: }
15480:
15481: void ems_unmap_page(int physical)
15482: {
15483: if(ems_pages[physical].mapped) {
15484: int handle = ems_pages[physical].handle;
15485: int logical = ems_pages[physical].page;
15486:
1.1.1.32 root 15487: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 15488: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
15489: }
15490: ems_pages[physical].mapped = false;
15491: }
15492: }
15493:
1.1.1.25 root 15494: // dma
1.1 root 15495:
1.1.1.25 root 15496: void dma_init()
1.1 root 15497: {
1.1.1.26 root 15498: memset(dma, 0, sizeof(dma));
1.1.1.25 root 15499: for(int c = 0; c < 2; c++) {
1.1.1.26 root 15500: // for(int ch = 0; ch < 4; ch++) {
15501: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
15502: // }
1.1.1.25 root 15503: dma_reset(c);
15504: }
1.1 root 15505: }
15506:
1.1.1.25 root 15507: void dma_reset(int c)
1.1 root 15508: {
1.1.1.25 root 15509: dma[c].low_high = false;
15510: dma[c].cmd = dma[c].req = dma[c].tc = 0;
15511: dma[c].mask = 0xff;
15512: }
15513:
15514: void dma_write(int c, UINT32 addr, UINT8 data)
15515: {
15516: int ch = (addr >> 1) & 3;
15517: UINT8 bit = 1 << (data & 3);
15518:
15519: switch(addr & 0x0f) {
15520: case 0x00: case 0x02: case 0x04: case 0x06:
15521: if(dma[c].low_high) {
15522: dma[c].ch[ch].bareg.b.h = data;
1.1 root 15523: } else {
1.1.1.25 root 15524: dma[c].ch[ch].bareg.b.l = data;
15525: }
15526: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
15527: dma[c].low_high = !dma[c].low_high;
15528: break;
15529: case 0x01: case 0x03: case 0x05: case 0x07:
15530: if(dma[c].low_high) {
15531: dma[c].ch[ch].bcreg.b.h = data;
15532: } else {
15533: dma[c].ch[ch].bcreg.b.l = data;
15534: }
15535: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
15536: dma[c].low_high = !dma[c].low_high;
15537: break;
15538: case 0x08:
15539: // command register
15540: dma[c].cmd = data;
15541: break;
15542: case 0x09:
15543: // dma[c].request register
15544: if(data & 4) {
15545: if(!(dma[c].req & bit)) {
15546: dma[c].req |= bit;
15547: // dma_run(c, ch);
15548: }
15549: } else {
15550: dma[c].req &= ~bit;
15551: }
15552: break;
15553: case 0x0a:
15554: // single mask register
15555: if(data & 4) {
15556: dma[c].mask |= bit;
15557: } else {
15558: dma[c].mask &= ~bit;
15559: }
15560: break;
15561: case 0x0b:
15562: // mode register
15563: dma[c].ch[data & 3].mode = data;
15564: break;
15565: case 0x0c:
15566: dma[c].low_high = false;
15567: break;
15568: case 0x0d:
15569: // clear master
15570: dma_reset(c);
15571: break;
15572: case 0x0e:
15573: // clear mask register
15574: dma[c].mask = 0;
15575: break;
15576: case 0x0f:
15577: // all mask register
15578: dma[c].mask = data & 0x0f;
15579: break;
15580: }
15581: }
15582:
15583: UINT8 dma_read(int c, UINT32 addr)
15584: {
15585: int ch = (addr >> 1) & 3;
15586: UINT8 val = 0xff;
15587:
15588: switch(addr & 0x0f) {
15589: case 0x00: case 0x02: case 0x04: case 0x06:
15590: if(dma[c].low_high) {
15591: val = dma[c].ch[ch].areg.b.h;
15592: } else {
15593: val = dma[c].ch[ch].areg.b.l;
15594: }
15595: dma[c].low_high = !dma[c].low_high;
15596: return(val);
15597: case 0x01: case 0x03: case 0x05: case 0x07:
15598: if(dma[c].low_high) {
15599: val = dma[c].ch[ch].creg.b.h;
15600: } else {
15601: val = dma[c].ch[ch].creg.b.l;
15602: }
15603: dma[c].low_high = !dma[c].low_high;
15604: return(val);
15605: case 0x08:
15606: // status register
15607: val = (dma[c].req << 4) | dma[c].tc;
15608: dma[c].tc = 0;
15609: return(val);
15610: case 0x0d:
1.1.1.26 root 15611: // temporary register (intel 82374 does not support)
1.1.1.25 root 15612: return(dma[c].tmp & 0xff);
1.1.1.26 root 15613: case 0x0f:
15614: // mask register (intel 82374 does support)
15615: return(dma[c].mask);
1.1.1.25 root 15616: }
15617: return(0xff);
15618: }
15619:
15620: void dma_page_write(int c, int ch, UINT8 data)
15621: {
15622: dma[c].ch[ch].pagereg = data;
15623: }
15624:
15625: UINT8 dma_page_read(int c, int ch)
15626: {
15627: return(dma[c].ch[ch].pagereg);
15628: }
15629:
15630: void dma_run(int c, int ch)
15631: {
15632: UINT8 bit = 1 << ch;
15633:
15634: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
15635: // execute dma
15636: while(dma[c].req & bit) {
15637: if(ch == 0 && (dma[c].cmd & 0x01)) {
15638: // memory -> memory
15639: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
15640: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
15641:
15642: if(c == 0) {
15643: dma[c].tmp = read_byte(saddr);
15644: write_byte(daddr, dma[c].tmp);
15645: } else {
15646: dma[c].tmp = read_word(saddr << 1);
15647: write_word(daddr << 1, dma[c].tmp);
15648: }
15649: if(!(dma[c].cmd & 0x02)) {
15650: if(dma[c].ch[0].mode & 0x20) {
15651: dma[c].ch[0].areg.w--;
15652: if(dma[c].ch[0].areg.w == 0xffff) {
15653: dma[c].ch[0].pagereg--;
15654: }
15655: } else {
15656: dma[c].ch[0].areg.w++;
15657: if(dma[c].ch[0].areg.w == 0) {
15658: dma[c].ch[0].pagereg++;
15659: }
15660: }
15661: }
15662: if(dma[c].ch[1].mode & 0x20) {
15663: dma[c].ch[1].areg.w--;
15664: if(dma[c].ch[1].areg.w == 0xffff) {
15665: dma[c].ch[1].pagereg--;
15666: }
15667: } else {
15668: dma[c].ch[1].areg.w++;
15669: if(dma[c].ch[1].areg.w == 0) {
15670: dma[c].ch[1].pagereg++;
15671: }
15672: }
15673:
15674: // check dma condition
15675: if(dma[c].ch[0].creg.w-- == 0) {
15676: if(dma[c].ch[0].mode & 0x10) {
15677: // self initialize
15678: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
15679: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
15680: } else {
15681: // dma[c].mask |= bit;
15682: }
15683: }
15684: if(dma[c].ch[1].creg.w-- == 0) {
15685: // terminal count
15686: if(dma[c].ch[1].mode & 0x10) {
15687: // self initialize
15688: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
15689: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
15690: } else {
15691: dma[c].mask |= bit;
15692: }
15693: dma[c].req &= ~bit;
15694: dma[c].tc |= bit;
15695: }
15696: } else {
15697: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
15698:
15699: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
15700: // verify
15701: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
15702: // io -> memory
15703: if(c == 0) {
15704: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
15705: write_byte(addr, dma[c].tmp);
15706: } else {
15707: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
15708: write_word(addr << 1, dma[c].tmp);
15709: }
15710: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
15711: // memory -> io
15712: if(c == 0) {
15713: dma[c].tmp = read_byte(addr);
15714: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
15715: } else {
15716: dma[c].tmp = read_word(addr << 1);
15717: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
15718: }
15719: }
15720: if(dma[c].ch[ch].mode & 0x20) {
15721: dma[c].ch[ch].areg.w--;
15722: if(dma[c].ch[ch].areg.w == 0xffff) {
15723: dma[c].ch[ch].pagereg--;
15724: }
15725: } else {
15726: dma[c].ch[ch].areg.w++;
15727: if(dma[c].ch[ch].areg.w == 0) {
15728: dma[c].ch[ch].pagereg++;
15729: }
15730: }
15731:
15732: // check dma condition
15733: if(dma[c].ch[ch].creg.w-- == 0) {
15734: // terminal count
15735: if(dma[c].ch[ch].mode & 0x10) {
15736: // self initialize
15737: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
15738: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
15739: } else {
15740: dma[c].mask |= bit;
15741: }
15742: dma[c].req &= ~bit;
15743: dma[c].tc |= bit;
15744: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
15745: // single mode
15746: break;
15747: }
15748: }
15749: }
15750: }
15751: }
15752:
15753: // pic
15754:
15755: void pic_init()
15756: {
15757: memset(pic, 0, sizeof(pic));
15758: pic[0].imr = pic[1].imr = 0xff;
15759:
15760: // from bochs bios
15761: pic_write(0, 0, 0x11); // icw1 = 11h
15762: pic_write(0, 1, 0x08); // icw2 = 08h
15763: pic_write(0, 1, 0x04); // icw3 = 04h
15764: pic_write(0, 1, 0x01); // icw4 = 01h
15765: pic_write(0, 1, 0xb8); // ocw1 = b8h
15766: pic_write(1, 0, 0x11); // icw1 = 11h
15767: pic_write(1, 1, 0x70); // icw2 = 70h
15768: pic_write(1, 1, 0x02); // icw3 = 02h
15769: pic_write(1, 1, 0x01); // icw4 = 01h
15770: }
15771:
15772: void pic_write(int c, UINT32 addr, UINT8 data)
15773: {
15774: if(addr & 1) {
15775: if(pic[c].icw2_r) {
15776: // icw2
15777: pic[c].icw2 = data;
15778: pic[c].icw2_r = 0;
15779: } else if(pic[c].icw3_r) {
15780: // icw3
15781: pic[c].icw3 = data;
15782: pic[c].icw3_r = 0;
15783: } else if(pic[c].icw4_r) {
15784: // icw4
15785: pic[c].icw4 = data;
15786: pic[c].icw4_r = 0;
15787: } else {
15788: // ocw1
1.1 root 15789: pic[c].imr = data;
15790: }
15791: } else {
15792: if(data & 0x10) {
15793: // icw1
15794: pic[c].icw1 = data;
15795: pic[c].icw2_r = 1;
15796: pic[c].icw3_r = (data & 2) ? 0 : 1;
15797: pic[c].icw4_r = data & 1;
15798: pic[c].irr = 0;
15799: pic[c].isr = 0;
15800: pic[c].imr = 0;
15801: pic[c].prio = 0;
15802: if(!(pic[c].icw1 & 1)) {
15803: pic[c].icw4 = 0;
15804: }
15805: pic[c].ocw3 = 0;
15806: } else if(data & 8) {
15807: // ocw3
15808: if(!(data & 2)) {
15809: data = (data & ~1) | (pic[c].ocw3 & 1);
15810: }
15811: if(!(data & 0x40)) {
15812: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
15813: }
15814: pic[c].ocw3 = data;
15815: } else {
15816: // ocw2
15817: int level = 0;
15818: if(data & 0x40) {
15819: level = data & 7;
15820: } else {
15821: if(!pic[c].isr) {
15822: return;
15823: }
15824: level = pic[c].prio;
15825: while(!(pic[c].isr & (1 << level))) {
15826: level = (level + 1) & 7;
15827: }
15828: }
15829: if(data & 0x80) {
15830: pic[c].prio = (level + 1) & 7;
15831: }
15832: if(data & 0x20) {
15833: pic[c].isr &= ~(1 << level);
15834: }
15835: }
15836: }
15837: pic_update();
15838: }
15839:
15840: UINT8 pic_read(int c, UINT32 addr)
15841: {
15842: if(addr & 1) {
15843: return(pic[c].imr);
15844: } else {
15845: // polling mode is not supported...
15846: //if(pic[c].ocw3 & 4) {
15847: // return ???;
15848: //}
15849: if(pic[c].ocw3 & 1) {
15850: return(pic[c].isr);
15851: } else {
15852: return(pic[c].irr);
15853: }
15854: }
15855: }
15856:
15857: void pic_req(int c, int level, int signal)
15858: {
15859: if(signal) {
15860: pic[c].irr |= (1 << level);
15861: } else {
15862: pic[c].irr &= ~(1 << level);
15863: }
15864: pic_update();
15865: }
15866:
15867: int pic_ack()
15868: {
15869: // ack (INTA=L)
15870: pic[pic_req_chip].isr |= pic_req_bit;
15871: pic[pic_req_chip].irr &= ~pic_req_bit;
15872: if(pic_req_chip > 0) {
15873: // update isr and irr of master
15874: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
15875: pic[pic_req_chip - 1].isr |= slave;
15876: pic[pic_req_chip - 1].irr &= ~slave;
15877: }
15878: //if(pic[pic_req_chip].icw4 & 1) {
15879: // 8086 mode
15880: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
15881: //} else {
15882: // // 8080 mode
15883: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
15884: // if(pic[pic_req_chip].icw1 & 4) {
15885: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
15886: // } else {
15887: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
15888: // }
15889: // vector = 0xcd | (addr << 8);
15890: //}
15891: if(pic[pic_req_chip].icw4 & 2) {
15892: // auto eoi
15893: pic[pic_req_chip].isr &= ~pic_req_bit;
15894: }
15895: return(vector);
15896: }
15897:
15898: void pic_update()
15899: {
15900: for(int c = 0; c < 2; c++) {
15901: UINT8 irr = pic[c].irr;
15902: if(c + 1 < 2) {
15903: // this is master
15904: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
15905: // request from slave
15906: irr |= 1 << (pic[c + 1].icw3 & 7);
15907: }
15908: }
15909: irr &= (~pic[c].imr);
15910: if(!irr) {
15911: break;
15912: }
15913: if(!(pic[c].ocw3 & 0x20)) {
15914: irr |= pic[c].isr;
15915: }
15916: int level = pic[c].prio;
15917: UINT8 bit = 1 << level;
15918: while(!(irr & bit)) {
15919: level = (level + 1) & 7;
15920: bit = 1 << level;
15921: }
15922: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
15923: // check slave
15924: continue;
15925: }
15926: if(pic[c].isr & bit) {
15927: break;
15928: }
15929: // interrupt request
15930: pic_req_chip = c;
15931: pic_req_level = level;
15932: pic_req_bit = bit;
1.1.1.3 root 15933: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 15934: return;
15935: }
1.1.1.3 root 15936: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 15937: }
1.1 root 15938:
1.1.1.25 root 15939: // pio
15940:
15941: void pio_init()
15942: {
1.1.1.26 root 15943: memset(pio, 0, sizeof(pio));
1.1.1.25 root 15944: for(int c = 0; c < 2; c++) {
15945: pio[c].stat = 0xde;
15946: pio[c].ctrl = 0x0c;
15947: }
15948: }
15949:
15950: void pio_write(int c, UINT32 addr, UINT8 data)
15951: {
15952: switch(addr & 3) {
15953: case 0:
15954: pio[c].data = data;
15955: break;
15956: case 2:
15957: pio[c].ctrl = data;
15958: break;
15959: }
15960: }
15961:
15962: UINT8 pio_read(int c, UINT32 addr)
15963: {
15964: switch(addr & 3) {
15965: case 0:
15966: return(pio[c].data);
15967: case 1:
15968: return(pio[c].stat);
15969: case 2:
15970: return(pio[c].ctrl);
15971: }
15972: return(0xff);
15973: }
15974:
1.1 root 15975: // pit
15976:
1.1.1.22 root 15977: #define PIT_FREQ 1193182ULL
1.1 root 15978: #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)
15979:
15980: void pit_init()
15981: {
1.1.1.8 root 15982: memset(pit, 0, sizeof(pit));
1.1 root 15983: for(int ch = 0; ch < 3; ch++) {
15984: pit[ch].count = 0x10000;
15985: pit[ch].ctrl_reg = 0x34;
15986: pit[ch].mode = 3;
15987: }
15988:
15989: // from bochs bios
15990: pit_write(3, 0x34);
15991: pit_write(0, 0x00);
15992: pit_write(0, 0x00);
15993: }
15994:
15995: void pit_write(int ch, UINT8 val)
15996: {
1.1.1.8 root 15997: #ifndef PIT_ALWAYS_RUNNING
1.1 root 15998: if(!pit_active) {
15999: pit_active = 1;
16000: pit_init();
16001: }
1.1.1.8 root 16002: #endif
1.1 root 16003: switch(ch) {
16004: case 0:
16005: case 1:
16006: case 2:
16007: // write count register
16008: if(!pit[ch].low_write && !pit[ch].high_write) {
16009: if(pit[ch].ctrl_reg & 0x10) {
16010: pit[ch].low_write = 1;
16011: }
16012: if(pit[ch].ctrl_reg & 0x20) {
16013: pit[ch].high_write = 1;
16014: }
16015: }
16016: if(pit[ch].low_write) {
16017: pit[ch].count_reg = val;
16018: pit[ch].low_write = 0;
16019: } else if(pit[ch].high_write) {
16020: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
16021: pit[ch].count_reg = val << 8;
16022: } else {
16023: pit[ch].count_reg |= val << 8;
16024: }
16025: pit[ch].high_write = 0;
16026: }
16027: // start count
1.1.1.8 root 16028: if(!pit[ch].low_write && !pit[ch].high_write) {
16029: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
16030: pit[ch].count = PIT_COUNT_VALUE(ch);
16031: pit[ch].prev_time = timeGetTime();
16032: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 16033: }
16034: }
16035: break;
16036: case 3: // ctrl reg
16037: if((val & 0xc0) == 0xc0) {
16038: // i8254 read-back command
16039: for(ch = 0; ch < 3; ch++) {
16040: if(!(val & 0x10) && !pit[ch].status_latched) {
16041: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
16042: pit[ch].status_latched = 1;
16043: }
16044: if(!(val & 0x20) && !pit[ch].count_latched) {
16045: pit_latch_count(ch);
16046: }
16047: }
16048: break;
16049: }
16050: ch = (val >> 6) & 3;
16051: if(val & 0x30) {
1.1.1.35 root 16052: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
1.1 root 16053: pit[ch].mode = modes[(val >> 1) & 7];
16054: pit[ch].count_latched = 0;
16055: pit[ch].low_read = pit[ch].high_read = 0;
16056: pit[ch].low_write = pit[ch].high_write = 0;
16057: pit[ch].ctrl_reg = val;
16058: // stop count
1.1.1.8 root 16059: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 16060: pit[ch].count_reg = 0;
16061: } else if(!pit[ch].count_latched) {
16062: pit_latch_count(ch);
16063: }
16064: break;
16065: }
16066: }
16067:
16068: UINT8 pit_read(int ch)
16069: {
1.1.1.8 root 16070: #ifndef PIT_ALWAYS_RUNNING
1.1 root 16071: if(!pit_active) {
16072: pit_active = 1;
16073: pit_init();
16074: }
1.1.1.8 root 16075: #endif
1.1 root 16076: switch(ch) {
16077: case 0:
16078: case 1:
16079: case 2:
16080: if(pit[ch].status_latched) {
16081: pit[ch].status_latched = 0;
16082: return(pit[ch].status);
16083: }
16084: // if not latched, through current count
16085: if(!pit[ch].count_latched) {
16086: if(!pit[ch].low_read && !pit[ch].high_read) {
16087: pit_latch_count(ch);
16088: }
16089: }
16090: // return latched count
16091: if(pit[ch].low_read) {
16092: pit[ch].low_read = 0;
16093: if(!pit[ch].high_read) {
16094: pit[ch].count_latched = 0;
16095: }
16096: return(pit[ch].latch & 0xff);
16097: } else if(pit[ch].high_read) {
16098: pit[ch].high_read = 0;
16099: pit[ch].count_latched = 0;
16100: return((pit[ch].latch >> 8) & 0xff);
16101: }
16102: }
16103: return(0xff);
16104: }
16105:
1.1.1.8 root 16106: int pit_run(int ch, UINT32 cur_time)
1.1 root 16107: {
1.1.1.8 root 16108: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 16109: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 16110: pit[ch].prev_time = pit[ch].expired_time;
16111: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
16112: if(cur_time >= pit[ch].expired_time) {
16113: pit[ch].prev_time = cur_time;
16114: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 16115: }
1.1.1.8 root 16116: return(1);
1.1 root 16117: }
1.1.1.8 root 16118: return(0);
1.1 root 16119: }
16120:
16121: void pit_latch_count(int ch)
16122: {
1.1.1.8 root 16123: if(pit[ch].expired_time != 0) {
1.1.1.26 root 16124: UINT32 cur_time = timeGetTime();
1.1.1.8 root 16125: pit_run(ch, cur_time);
16126: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 16127: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
16128:
16129: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
16130: // decrement counter in 1msec period
16131: if(pit[ch].next_latch == 0) {
16132: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
16133: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
16134: }
16135: if(pit[ch].latch > pit[ch].next_latch) {
16136: pit[ch].latch--;
16137: }
16138: } else {
16139: pit[ch].prev_latch = pit[ch].latch = latch;
16140: pit[ch].next_latch = 0;
16141: }
1.1.1.8 root 16142: } else {
16143: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 16144: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 16145: }
16146: pit[ch].count_latched = 1;
16147: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
16148: // lower byte
16149: pit[ch].low_read = 1;
16150: pit[ch].high_read = 0;
16151: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
16152: // upper byte
16153: pit[ch].low_read = 0;
16154: pit[ch].high_read = 1;
16155: } else {
16156: // lower -> upper
1.1.1.14 root 16157: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 16158: }
16159: }
16160:
1.1.1.8 root 16161: int pit_get_expired_time(int ch)
1.1 root 16162: {
1.1.1.22 root 16163: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
16164: UINT64 val = pit[ch].accum >> 10;
16165: pit[ch].accum -= val << 10;
16166: return((val != 0) ? val : 1);
1.1.1.8 root 16167: }
16168:
1.1.1.25 root 16169: // sio
16170:
16171: void sio_init()
16172: {
1.1.1.26 root 16173: memset(sio, 0, sizeof(sio));
16174: memset(sio_mt, 0, sizeof(sio_mt));
16175:
1.1.1.29 root 16176: for(int c = 0; c < 4; c++) {
1.1.1.25 root 16177: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
16178: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
16179:
16180: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
16181: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 16182: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
16183: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 16184: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
16185: sio[c].irq_identify = 0x01; // no pending irq
16186:
16187: InitializeCriticalSection(&sio_mt[c].csSendData);
16188: InitializeCriticalSection(&sio_mt[c].csRecvData);
16189: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
16190: InitializeCriticalSection(&sio_mt[c].csLineStat);
16191: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
16192: InitializeCriticalSection(&sio_mt[c].csModemStat);
16193:
1.1.1.26 root 16194: if(sio_port_number[c] != 0) {
1.1.1.25 root 16195: sio[c].channel = c;
16196: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
16197: }
16198: }
16199: }
16200:
16201: void sio_finish()
16202: {
1.1.1.29 root 16203: for(int c = 0; c < 4; c++) {
1.1.1.25 root 16204: if(sio_mt[c].hThread != NULL) {
16205: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
16206: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 16207: sio_mt[c].hThread = NULL;
1.1.1.25 root 16208: }
16209: DeleteCriticalSection(&sio_mt[c].csSendData);
16210: DeleteCriticalSection(&sio_mt[c].csRecvData);
16211: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
16212: DeleteCriticalSection(&sio_mt[c].csLineStat);
16213: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
16214: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 16215: }
16216: sio_release();
16217: }
16218:
16219: void sio_release()
16220: {
1.1.1.29 root 16221: for(int c = 0; c < 4; c++) {
1.1.1.28 root 16222: // sio_thread() may access the resources :-(
1.1.1.32 root 16223: bool running = (sio_mt[c].hThread != NULL);
16224:
16225: if(running) {
16226: EnterCriticalSection(&sio_mt[c].csSendData);
16227: }
16228: if(sio[c].send_buffer != NULL) {
16229: sio[c].send_buffer->release();
16230: delete sio[c].send_buffer;
16231: sio[c].send_buffer = NULL;
16232: }
16233: if(running) {
16234: LeaveCriticalSection(&sio_mt[c].csSendData);
16235: EnterCriticalSection(&sio_mt[c].csRecvData);
16236: }
16237: if(sio[c].recv_buffer != NULL) {
16238: sio[c].recv_buffer->release();
16239: delete sio[c].recv_buffer;
16240: sio[c].recv_buffer = NULL;
16241: }
16242: if(running) {
16243: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 16244: }
1.1.1.25 root 16245: }
16246: }
16247:
16248: void sio_write(int c, UINT32 addr, UINT8 data)
16249: {
16250: switch(addr & 7) {
16251: case 0:
16252: if(sio[c].selector & 0x80) {
16253: if(sio[c].divisor.b.l != data) {
16254: EnterCriticalSection(&sio_mt[c].csLineCtrl);
16255: sio[c].divisor.b.l = data;
16256: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
16257: }
16258: } else {
16259: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 16260: if(sio[c].send_buffer != NULL) {
16261: sio[c].send_buffer->write(data);
16262: }
1.1.1.25 root 16263: // transmitter holding/shift registers are not empty
16264: sio[c].line_stat_buf &= ~0x60;
16265: LeaveCriticalSection(&sio_mt[c].csSendData);
16266:
16267: if(sio[c].irq_enable & 0x02) {
16268: sio_update_irq(c);
16269: }
16270: }
16271: break;
16272: case 1:
16273: if(sio[c].selector & 0x80) {
16274: if(sio[c].divisor.b.h != data) {
16275: EnterCriticalSection(&sio_mt[c].csLineCtrl);
16276: sio[c].divisor.b.h = data;
16277: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
16278: }
16279: } else {
16280: if(sio[c].irq_enable != data) {
16281: sio[c].irq_enable = data;
16282: sio_update_irq(c);
16283: }
16284: }
16285: break;
16286: case 3:
16287: {
16288: UINT8 line_ctrl = data & 0x3f;
16289: bool set_brk = ((data & 0x40) != 0);
16290:
16291: if(sio[c].line_ctrl != line_ctrl) {
16292: EnterCriticalSection(&sio_mt[c].csLineCtrl);
16293: sio[c].line_ctrl = line_ctrl;
16294: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
16295: }
16296: if(sio[c].set_brk != set_brk) {
16297: EnterCriticalSection(&sio_mt[c].csModemCtrl);
16298: sio[c].set_brk = set_brk;
16299: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
16300: }
16301: }
16302: sio[c].selector = data;
16303: break;
16304: case 4:
16305: {
16306: bool set_dtr = ((data & 0x01) != 0);
16307: bool set_rts = ((data & 0x02) != 0);
16308:
16309: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 16310: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 16311: sio[c].set_dtr = set_dtr;
16312: sio[c].set_rts = set_rts;
1.1.1.26 root 16313: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
16314:
16315: bool state_changed = false;
16316:
16317: EnterCriticalSection(&sio_mt[c].csModemStat);
16318: if(set_dtr) {
16319: sio[c].modem_stat |= 0x20; // dsr on
16320: } else {
16321: sio[c].modem_stat &= ~0x20; // dsr off
16322: }
16323: if(set_rts) {
16324: sio[c].modem_stat |= 0x10; // cts on
16325: } else {
16326: sio[c].modem_stat &= ~0x10; // cts off
16327: }
16328: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
16329: if(!(sio[c].modem_stat & 0x02)) {
16330: if(sio[c].irq_enable & 0x08) {
16331: state_changed = true;
16332: }
16333: sio[c].modem_stat |= 0x02;
16334: }
16335: }
16336: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
16337: if(!(sio[c].modem_stat & 0x01)) {
16338: if(sio[c].irq_enable & 0x08) {
16339: state_changed = true;
16340: }
16341: sio[c].modem_stat |= 0x01;
16342: }
16343: }
16344: LeaveCriticalSection(&sio_mt[c].csModemStat);
16345:
16346: if(state_changed) {
16347: sio_update_irq(c);
16348: }
1.1.1.25 root 16349: }
16350: }
16351: sio[c].modem_ctrl = data;
16352: break;
16353: case 7:
16354: sio[c].scratch = data;
16355: break;
16356: }
16357: }
16358:
16359: UINT8 sio_read(int c, UINT32 addr)
16360: {
16361: switch(addr & 7) {
16362: case 0:
16363: if(sio[c].selector & 0x80) {
16364: return(sio[c].divisor.b.l);
16365: } else {
16366: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 16367: UINT8 data = 0;
16368: if(sio[c].recv_buffer != NULL) {
16369: data = sio[c].recv_buffer->read();
16370: }
1.1.1.25 root 16371: // data is not ready
16372: sio[c].line_stat_buf &= ~0x01;
16373: LeaveCriticalSection(&sio_mt[c].csRecvData);
16374:
16375: if(sio[c].irq_enable & 0x01) {
16376: sio_update_irq(c);
16377: }
16378: return(data);
16379: }
16380: case 1:
16381: if(sio[c].selector & 0x80) {
16382: return(sio[c].divisor.b.h);
16383: } else {
16384: return(sio[c].irq_enable);
16385: }
16386: case 2:
16387: return(sio[c].irq_identify);
16388: case 3:
16389: return(sio[c].selector);
16390: case 4:
16391: return(sio[c].modem_ctrl);
16392: case 5:
16393: {
16394: EnterCriticalSection(&sio_mt[c].csLineStat);
16395: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
16396: sio[c].line_stat_err = 0x00;
16397: LeaveCriticalSection(&sio_mt[c].csLineStat);
16398:
16399: bool state_changed = false;
16400:
16401: if((sio[c].line_stat_buf & 0x60) == 0x00) {
16402: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 16403: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 16404: // transmitter holding register will be empty first
16405: if(sio[c].irq_enable & 0x02) {
16406: state_changed = true;
16407: }
16408: sio[c].line_stat_buf |= 0x20;
16409: }
16410: LeaveCriticalSection(&sio_mt[c].csSendData);
16411: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
16412: // transmitter shift register will be empty later
16413: sio[c].line_stat_buf |= 0x40;
16414: }
16415: if(!(sio[c].line_stat_buf & 0x01)) {
16416: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 16417: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 16418: // data is ready
16419: if(sio[c].irq_enable & 0x01) {
16420: state_changed = true;
16421: }
16422: sio[c].line_stat_buf |= 0x01;
16423: }
16424: LeaveCriticalSection(&sio_mt[c].csRecvData);
16425: }
16426: if(state_changed) {
16427: sio_update_irq(c);
16428: }
16429: return(val);
16430: }
16431: case 6:
16432: {
16433: EnterCriticalSection(&sio_mt[c].csModemStat);
16434: UINT8 val = sio[c].modem_stat;
16435: sio[c].modem_stat &= 0xf0;
16436: sio[c].prev_modem_stat = sio[c].modem_stat;
16437: LeaveCriticalSection(&sio_mt[c].csModemStat);
16438:
16439: if(sio[c].modem_ctrl & 0x10) {
16440: // loop-back
16441: val &= 0x0f;
16442: val |= (sio[c].modem_ctrl & 0x0c) << 4;
16443: val |= (sio[c].modem_ctrl & 0x01) << 5;
16444: val |= (sio[c].modem_ctrl & 0x02) << 3;
16445: }
16446: return(val);
16447: }
16448: case 7:
16449: return(sio[c].scratch);
16450: }
16451: return(0xff);
16452: }
16453:
16454: void sio_update(int c)
16455: {
16456: if((sio[c].line_stat_buf & 0x60) == 0x00) {
16457: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 16458: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 16459: // transmitter holding/shift registers will be empty
16460: sio[c].line_stat_buf |= 0x60;
16461: }
16462: LeaveCriticalSection(&sio_mt[c].csSendData);
16463: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
16464: // transmitter shift register will be empty
16465: sio[c].line_stat_buf |= 0x40;
16466: }
16467: if(!(sio[c].line_stat_buf & 0x01)) {
16468: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 16469: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 16470: // data is ready
16471: sio[c].line_stat_buf |= 0x01;
16472: }
16473: LeaveCriticalSection(&sio_mt[c].csRecvData);
16474: }
16475: sio_update_irq(c);
16476: }
16477:
16478: void sio_update_irq(int c)
16479: {
16480: int level = -1;
16481:
16482: if(sio[c].irq_enable & 0x08) {
16483: EnterCriticalSection(&sio_mt[c].csModemStat);
16484: if((sio[c].modem_stat & 0x0f) != 0) {
16485: level = 0;
16486: }
16487: EnterCriticalSection(&sio_mt[c].csModemStat);
16488: }
16489: if(sio[c].irq_enable & 0x02) {
16490: if(sio[c].line_stat_buf & 0x20) {
16491: level = 1;
16492: }
16493: }
16494: if(sio[c].irq_enable & 0x01) {
16495: if(sio[c].line_stat_buf & 0x01) {
16496: level = 2;
16497: }
16498: }
16499: if(sio[c].irq_enable & 0x04) {
16500: EnterCriticalSection(&sio_mt[c].csLineStat);
16501: if(sio[c].line_stat_err != 0) {
16502: level = 3;
16503: }
16504: LeaveCriticalSection(&sio_mt[c].csLineStat);
16505: }
1.1.1.29 root 16506:
16507: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 16508: if(level != -1) {
16509: sio[c].irq_identify = level << 1;
1.1.1.29 root 16510: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 16511: } else {
16512: sio[c].irq_identify = 1;
1.1.1.29 root 16513: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 16514: }
16515: }
16516:
16517: DWORD WINAPI sio_thread(void *lpx)
16518: {
16519: volatile sio_t *p = (sio_t *)lpx;
16520: sio_mt_t *q = &sio_mt[p->channel];
16521:
16522: char name[] = "COM1";
1.1.1.26 root 16523: name[3] = '0' + sio_port_number[p->channel];
16524: HANDLE hComm = NULL;
16525: COMMPROP commProp;
16526: DCB dcb;
16527: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
16528: BYTE bytBuffer[SIO_BUFFER_SIZE];
16529:
16530: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
16531: if(GetCommProperties(hComm, &commProp)) {
16532: dwSettableBaud = commProp.dwSettableBaud;
16533: }
1.1.1.25 root 16534: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 16535: // EscapeCommFunction(hComm, SETRTS);
16536: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 16537:
16538: while(!m_halted) {
16539: // setup comm port
16540: bool comm_state_changed = false;
16541:
16542: EnterCriticalSection(&q->csLineCtrl);
16543: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
16544: p->prev_divisor = p->divisor.w;
16545: p->prev_line_ctrl = p->line_ctrl;
16546: comm_state_changed = true;
16547: }
16548: LeaveCriticalSection(&q->csLineCtrl);
16549:
16550: if(comm_state_changed) {
1.1.1.26 root 16551: if(GetCommState(hComm, &dcb)) {
16552: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
16553: DWORD baud = 115200 / p->prev_divisor;
16554: dcb.BaudRate = 9600; // default
16555:
16556: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
16557: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
16558: // 134.5bps is not supported ???
16559: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
16560: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
16561: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
16562: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
16563: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
16564: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
16565: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
16566: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
16567: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
16568: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
16569: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
16570: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
16571: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
16572:
16573: switch(p->prev_line_ctrl & 0x03) {
16574: case 0x00: dcb.ByteSize = 5; break;
16575: case 0x01: dcb.ByteSize = 6; break;
16576: case 0x02: dcb.ByteSize = 7; break;
16577: case 0x03: dcb.ByteSize = 8; break;
16578: }
16579: switch(p->prev_line_ctrl & 0x04) {
16580: case 0x00: dcb.StopBits = ONESTOPBIT; break;
16581: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
16582: }
16583: switch(p->prev_line_ctrl & 0x38) {
16584: case 0x08: dcb.Parity = ODDPARITY; break;
16585: case 0x18: dcb.Parity = EVENPARITY; break;
16586: case 0x28: dcb.Parity = MARKPARITY; break;
16587: case 0x38: dcb.Parity = SPACEPARITY; break;
16588: default: dcb.Parity = NOPARITY; break;
16589: }
16590: dcb.fBinary = TRUE;
16591: dcb.fParity = (dcb.Parity != NOPARITY);
16592: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
16593: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
16594: dcb.fDsrSensitivity = FALSE;//TRUE;
16595: dcb.fTXContinueOnXoff = TRUE;
16596: dcb.fOutX = dcb.fInX = FALSE;
16597: dcb.fErrorChar = FALSE;
16598: dcb.fNull = FALSE;
16599: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
16600: dcb.fAbortOnError = FALSE;
16601:
16602: SetCommState(hComm, &dcb);
1.1.1.25 root 16603: }
16604:
16605: // check again to apply all comm state changes
16606: Sleep(10);
16607: continue;
16608: }
16609:
16610: // set comm pins
16611: bool change_brk = false;
1.1.1.26 root 16612: // bool change_rts = false;
16613: // bool change_dtr = false;
1.1.1.25 root 16614:
16615: EnterCriticalSection(&q->csModemCtrl);
16616: if(p->prev_set_brk != p->set_brk) {
16617: p->prev_set_brk = p->set_brk;
16618: change_brk = true;
16619: }
1.1.1.26 root 16620: // if(p->prev_set_rts != p->set_rts) {
16621: // p->prev_set_rts = p->set_rts;
16622: // change_rts = true;
16623: // }
16624: // if(p->prev_set_dtr != p->set_dtr) {
16625: // p->prev_set_dtr = p->set_dtr;
16626: // change_dtr = true;
16627: // }
1.1.1.25 root 16628: LeaveCriticalSection(&q->csModemCtrl);
16629:
16630: if(change_brk) {
1.1.1.26 root 16631: static UINT32 clear_time = 0;
16632: if(p->prev_set_brk) {
16633: EscapeCommFunction(hComm, SETBREAK);
16634: clear_time = timeGetTime() + 200;
16635: } else {
16636: // keep break for at least 200msec
16637: UINT32 cur_time = timeGetTime();
16638: if(clear_time > cur_time) {
16639: Sleep(clear_time - cur_time);
16640: }
16641: EscapeCommFunction(hComm, CLRBREAK);
16642: }
1.1.1.25 root 16643: }
1.1.1.26 root 16644: // if(change_rts) {
16645: // if(p->prev_set_rts) {
16646: // EscapeCommFunction(hComm, SETRTS);
16647: // } else {
16648: // EscapeCommFunction(hComm, CLRRTS);
16649: // }
16650: // }
16651: // if(change_dtr) {
16652: // if(p->prev_set_dtr) {
16653: // EscapeCommFunction(hComm, SETDTR);
16654: // } else {
16655: // EscapeCommFunction(hComm, CLRDTR);
16656: // }
16657: // }
1.1.1.25 root 16658:
16659: // get comm pins
16660: DWORD dwModemStat = 0;
16661:
16662: if(GetCommModemStatus(hComm, &dwModemStat)) {
16663: EnterCriticalSection(&q->csModemStat);
16664: if(dwModemStat & MS_RLSD_ON) {
16665: p->modem_stat |= 0x80;
16666: } else {
16667: p->modem_stat &= ~0x80;
16668: }
16669: if(dwModemStat & MS_RING_ON) {
16670: p->modem_stat |= 0x40;
16671: } else {
16672: p->modem_stat &= ~0x40;
16673: }
1.1.1.26 root 16674: // if(dwModemStat & MS_DSR_ON) {
16675: // p->modem_stat |= 0x20;
16676: // } else {
16677: // p->modem_stat &= ~0x20;
16678: // }
16679: // if(dwModemStat & MS_CTS_ON) {
16680: // p->modem_stat |= 0x10;
16681: // } else {
16682: // p->modem_stat &= ~0x10;
16683: // }
1.1.1.25 root 16684: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
16685: p->modem_stat |= 0x08;
16686: }
16687: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
16688: p->modem_stat |= 0x04;
16689: }
1.1.1.26 root 16690: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
16691: // p->modem_stat |= 0x02;
16692: // }
16693: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
16694: // p->modem_stat |= 0x01;
16695: // }
1.1.1.25 root 16696: LeaveCriticalSection(&q->csModemStat);
16697: }
16698:
16699: // send data
16700: DWORD dwSend = 0;
16701:
16702: EnterCriticalSection(&q->csSendData);
1.1.1.32 root 16703: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 16704: bytBuffer[dwSend++] = p->send_buffer->read();
16705: }
16706: LeaveCriticalSection(&q->csSendData);
16707:
16708: if(dwSend != 0) {
16709: DWORD dwWritten = 0;
16710: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
16711: }
16712:
16713: // get line status and recv data
16714: DWORD dwLineStat = 0;
16715: COMSTAT comStat;
16716:
16717: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
16718: EnterCriticalSection(&q->csLineStat);
16719: if(dwLineStat & CE_BREAK) {
16720: p->line_stat_err |= 0x10;
16721: }
16722: if(dwLineStat & CE_FRAME) {
16723: p->line_stat_err |= 0x08;
16724: }
16725: if(dwLineStat & CE_RXPARITY) {
16726: p->line_stat_err |= 0x04;
16727: }
16728: if(dwLineStat & CE_OVERRUN) {
16729: p->line_stat_err |= 0x02;
16730: }
16731: LeaveCriticalSection(&q->csLineStat);
16732:
16733: if(comStat.cbInQue != 0) {
16734: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 16735: DWORD dwRecv = 0;
16736: if(p->recv_buffer != NULL) {
16737: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
16738: }
1.1.1.25 root 16739: LeaveCriticalSection(&q->csRecvData);
16740:
16741: if(dwRecv != 0) {
16742: DWORD dwRead = 0;
16743: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
16744: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 16745: if(p->recv_buffer != NULL) {
16746: for(int i = 0; i < dwRead; i++) {
16747: p->recv_buffer->write(bytBuffer[i]);
16748: }
1.1.1.25 root 16749: }
16750: LeaveCriticalSection(&q->csRecvData);
16751: }
16752: }
16753: }
16754: }
16755: Sleep(10);
16756: }
16757: CloseHandle(hComm);
16758: }
16759: return 0;
16760: }
16761:
1.1.1.8 root 16762: // cmos
16763:
16764: void cmos_init()
16765: {
16766: memset(cmos, 0, sizeof(cmos));
16767: cmos_addr = 0;
1.1 root 16768:
1.1.1.8 root 16769: // from DOSBox
16770: cmos_write(0x0a, 0x26);
16771: cmos_write(0x0b, 0x02);
16772: cmos_write(0x0d, 0x80);
1.1 root 16773: }
16774:
1.1.1.8 root 16775: void cmos_write(int addr, UINT8 val)
1.1 root 16776: {
1.1.1.8 root 16777: cmos[addr & 0x7f] = val;
16778: }
16779:
16780: #define CMOS_GET_TIME() { \
16781: UINT32 cur_sec = timeGetTime() / 1000 ; \
16782: if(prev_sec != cur_sec) { \
16783: GetLocalTime(&time); \
16784: prev_sec = cur_sec; \
16785: } \
1.1 root 16786: }
1.1.1.8 root 16787: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 16788:
1.1.1.8 root 16789: UINT8 cmos_read(int addr)
1.1 root 16790: {
1.1.1.8 root 16791: static SYSTEMTIME time;
16792: static UINT32 prev_sec = 0;
1.1 root 16793:
1.1.1.8 root 16794: switch(addr & 0x7f) {
16795: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
16796: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
16797: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
16798: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
16799: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
16800: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
16801: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
16802: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
16803: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
16804: case 0x15: return((MEMORY_END >> 10) & 0xff);
16805: case 0x16: return((MEMORY_END >> 18) & 0xff);
16806: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
16807: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
16808: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
16809: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
16810: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 16811: }
1.1.1.8 root 16812: return(cmos[addr & 0x7f]);
1.1 root 16813: }
16814:
1.1.1.7 root 16815: // kbd (a20)
16816:
16817: void kbd_init()
16818: {
1.1.1.8 root 16819: kbd_data = kbd_command = 0;
1.1.1.7 root 16820: kbd_status = 0x18;
16821: }
16822:
16823: UINT8 kbd_read_data()
16824: {
1.1.1.8 root 16825: kbd_status &= ~1;
1.1.1.7 root 16826: return(kbd_data);
16827: }
16828:
16829: void kbd_write_data(UINT8 val)
16830: {
16831: switch(kbd_command) {
16832: case 0xd1:
16833: i386_set_a20_line((val >> 1) & 1);
16834: break;
16835: }
16836: kbd_command = 0;
1.1.1.8 root 16837: kbd_status &= ~8;
1.1.1.7 root 16838: }
16839:
16840: UINT8 kbd_read_status()
16841: {
16842: return(kbd_status);
16843: }
16844:
16845: void kbd_write_command(UINT8 val)
16846: {
16847: switch(val) {
16848: case 0xd0:
16849: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 16850: kbd_status |= 1;
1.1.1.7 root 16851: break;
16852: case 0xdd:
16853: i386_set_a20_line(0);
16854: break;
16855: case 0xdf:
16856: i386_set_a20_line(1);
16857: break;
1.1.1.26 root 16858: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
16859: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 16860: if(!(val & 1)) {
1.1.1.8 root 16861: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 16862: // reset pic
16863: pic_init();
16864: pic[0].irr = pic[1].irr = 0x00;
16865: pic[0].imr = pic[1].imr = 0xff;
16866: }
16867: CPU_RESET_CALL(CPU_MODEL);
16868: i386_jmp_far(0x40, 0x67);
16869: }
16870: i386_set_a20_line((val >> 1) & 1);
16871: break;
16872: }
16873: kbd_command = val;
1.1.1.8 root 16874: kbd_status |= 8;
1.1.1.7 root 16875: }
16876:
1.1.1.9 root 16877: // vga
16878:
16879: UINT8 vga_read_status()
16880: {
16881: // 60hz
16882: static const int period[3] = {16, 17, 17};
16883: static int index = 0;
16884: UINT32 time = timeGetTime() % period[index];
16885:
16886: index = (index + 1) % 3;
1.1.1.14 root 16887: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 16888: }
16889:
1.1 root 16890: // i/o bus
16891:
1.1.1.29 root 16892: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
16893: //#define SW1US_PATCH
16894:
1.1.1.25 root 16895: UINT8 read_io_byte(offs_t addr)
1.1.1.33 root 16896: #ifdef USE_DEBUGGER
1.1.1.25 root 16897: {
1.1.1.33 root 16898: if(now_debugging) {
16899: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
16900: if(in_break_point.table[i].status == 1) {
16901: if(addr == in_break_point.table[i].addr) {
16902: in_break_point.hit = i + 1;
16903: now_suspended = true;
16904: break;
16905: }
16906: }
16907: }
1.1.1.25 root 16908: }
1.1.1.33 root 16909: return(debugger_read_io_byte(addr));
1.1.1.25 root 16910: }
1.1.1.33 root 16911: UINT8 debugger_read_io_byte(offs_t addr)
1.1.1.25 root 16912: #endif
1.1 root 16913: {
1.1.1.33 root 16914: UINT8 val = 0xff;
16915:
1.1 root 16916: switch(addr) {
1.1.1.29 root 16917: #ifdef SW1US_PATCH
16918: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
16919: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
1.1.1.33 root 16920: val = sio_read(0, addr - 1);
16921: break;
1.1.1.29 root 16922: #else
1.1.1.25 root 16923: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
16924: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1.1.1.33 root 16925: val = dma_read(0, addr);
16926: break;
1.1.1.29 root 16927: #endif
1.1.1.25 root 16928: case 0x20: case 0x21:
1.1.1.33 root 16929: val = pic_read(0, addr);
16930: break;
1.1.1.25 root 16931: case 0x40: case 0x41: case 0x42: case 0x43:
1.1.1.33 root 16932: val = pit_read(addr & 0x03);
16933: break;
1.1.1.7 root 16934: case 0x60:
1.1.1.33 root 16935: val = kbd_read_data();
16936: break;
1.1.1.9 root 16937: case 0x61:
1.1.1.33 root 16938: val = system_port;
16939: break;
1.1.1.7 root 16940: case 0x64:
1.1.1.33 root 16941: val = kbd_read_status();
16942: break;
1.1 root 16943: case 0x71:
1.1.1.33 root 16944: val = cmos_read(cmos_addr);
16945: break;
1.1.1.25 root 16946: case 0x81:
1.1.1.33 root 16947: val = dma_page_read(0, 2);
16948: break;
1.1.1.25 root 16949: case 0x82:
1.1.1.33 root 16950: val = dma_page_read(0, 3);
16951: break;
1.1.1.25 root 16952: case 0x83:
1.1.1.33 root 16953: val = dma_page_read(0, 1);
16954: break;
1.1.1.25 root 16955: case 0x87:
1.1.1.33 root 16956: val = dma_page_read(0, 0);
16957: break;
1.1.1.25 root 16958: case 0x89:
1.1.1.33 root 16959: val = dma_page_read(1, 2);
16960: break;
1.1.1.25 root 16961: case 0x8a:
1.1.1.33 root 16962: val = dma_page_read(1, 3);
16963: break;
1.1.1.25 root 16964: case 0x8b:
1.1.1.33 root 16965: val = dma_page_read(1, 1);
16966: break;
1.1.1.25 root 16967: case 0x8f:
1.1.1.33 root 16968: val = dma_page_read(1, 0);
16969: break;
1.1 root 16970: case 0x92:
1.1.1.33 root 16971: val = (m_a20_mask >> 19) & 2;
16972: break;
1.1.1.25 root 16973: case 0xa0: case 0xa1:
1.1.1.33 root 16974: val = pic_read(1, addr);
16975: break;
1.1.1.25 root 16976: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
16977: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.33 root 16978: val = dma_read(1, (addr - 0xc0) >> 1);
16979: break;
1.1.1.26 root 16980: // case 0x278: case 0x279: case 0x27a:
1.1.1.33 root 16981: // val = pio_read(1, addr);
16982: // break;
1.1.1.29 root 16983: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
1.1.1.33 root 16984: val = sio_read(3, addr);
16985: break;
1.1.1.25 root 16986: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
1.1.1.33 root 16987: val = sio_read(1, addr);
16988: break;
1.1.1.25 root 16989: case 0x378: case 0x379: case 0x37a:
1.1.1.33 root 16990: val = pio_read(0, addr);
16991: break;
1.1.1.25 root 16992: case 0x3ba: case 0x3da:
1.1.1.33 root 16993: val = vga_read_status();
16994: break;
1.1.1.29 root 16995: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
1.1.1.33 root 16996: val = sio_read(2, addr);
16997: break;
1.1.1.25 root 16998: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
1.1.1.33 root 16999: val = sio_read(0, addr);
17000: break;
1.1 root 17001: default:
1.1.1.33 root 17002: // fatalerror("unknown inb %4x\n", addr);
1.1 root 17003: break;
17004: }
1.1.1.33 root 17005: #ifdef ENABLE_DEBUG_IOPORT
17006: if(fp_debug_log != NULL) {
17007: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
17008: }
17009: #endif
17010: return(val);
1.1 root 17011: }
17012:
17013: UINT16 read_io_word(offs_t addr)
17014: {
17015: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
17016: }
17017:
1.1.1.33 root 17018: #ifdef USE_DEBUGGER
17019: UINT16 debugger_read_io_word(offs_t addr)
17020: {
17021: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
17022: }
17023: #endif
17024:
1.1 root 17025: UINT32 read_io_dword(offs_t addr)
17026: {
17027: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
17028: }
17029:
1.1.1.33 root 17030: #ifdef USE_DEBUGGER
17031: UINT32 debugger_read_io_dword(offs_t addr)
17032: {
17033: 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));
17034: }
17035: #endif
17036:
1.1 root 17037: void write_io_byte(offs_t addr, UINT8 val)
1.1.1.33 root 17038: #ifdef USE_DEBUGGER
17039: {
17040: if(now_debugging) {
17041: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
17042: if(out_break_point.table[i].status == 1) {
17043: if(addr == out_break_point.table[i].addr) {
17044: out_break_point.hit = i + 1;
17045: now_suspended = true;
17046: break;
17047: }
17048: }
17049: }
17050: }
17051: debugger_write_io_byte(addr, val);
17052: }
17053: void debugger_write_io_byte(offs_t addr, UINT8 val)
17054: #endif
1.1 root 17055: {
1.1.1.25 root 17056: #ifdef ENABLE_DEBUG_IOPORT
1.1.1.33 root 17057: if(fp_debug_log != NULL) {
17058: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
1.1.1.25 root 17059: }
17060: #endif
1.1 root 17061: switch(addr) {
1.1.1.29 root 17062: #ifdef SW1US_PATCH
17063: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
17064: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
17065: sio_write(0, addr - 1, val);
17066: break;
17067: #else
1.1.1.25 root 17068: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
17069: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
17070: dma_write(0, addr, val);
17071: break;
1.1.1.29 root 17072: #endif
1.1.1.25 root 17073: case 0x20: case 0x21:
1.1 root 17074: pic_write(0, addr, val);
17075: break;
1.1.1.25 root 17076: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 17077: pit_write(addr & 0x03, val);
17078: break;
1.1.1.7 root 17079: case 0x60:
17080: kbd_write_data(val);
17081: break;
1.1.1.9 root 17082: case 0x61:
17083: if((system_port & 3) != 3 && (val & 3) == 3) {
17084: // beep on
17085: // MessageBeep(-1);
17086: } else if((system_port & 3) == 3 && (val & 3) != 3) {
17087: // beep off
17088: }
17089: system_port = val;
17090: break;
1.1 root 17091: case 0x64:
1.1.1.7 root 17092: kbd_write_command(val);
1.1 root 17093: break;
17094: case 0x70:
17095: cmos_addr = val;
17096: break;
17097: case 0x71:
1.1.1.8 root 17098: cmos_write(cmos_addr, val);
1.1 root 17099: break;
1.1.1.25 root 17100: case 0x81:
17101: dma_page_write(0, 2, val);
17102: case 0x82:
17103: dma_page_write(0, 3, val);
17104: case 0x83:
17105: dma_page_write(0, 1, val);
17106: case 0x87:
17107: dma_page_write(0, 0, val);
17108: case 0x89:
17109: dma_page_write(1, 2, val);
17110: case 0x8a:
17111: dma_page_write(1, 3, val);
17112: case 0x8b:
17113: dma_page_write(1, 1, val);
17114: case 0x8f:
17115: dma_page_write(1, 0, val);
1.1 root 17116: case 0x92:
1.1.1.7 root 17117: i386_set_a20_line((val >> 1) & 1);
1.1 root 17118: break;
1.1.1.25 root 17119: case 0xa0: case 0xa1:
1.1 root 17120: pic_write(1, addr, val);
17121: break;
1.1.1.25 root 17122: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
17123: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 17124: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 17125: break;
1.1.1.35 root 17126: #ifdef USE_SERVICE_THREAD
17127: case 0xf7:
17128: // dummy i/o for BIOS/DOS service
1.1.1.36! root 17129: if(in_service && cursor_moved) {
! 17130: // update cursor position before service is done
! 17131: pcbios_update_cursor_position();
! 17132: cursor_moved = false;
! 17133: }
1.1.1.35 root 17134: finish_service_loop();
17135: break;
17136: #endif
1.1.1.26 root 17137: // case 0x278: case 0x279: case 0x27a:
17138: // pio_write(1, addr, val);
17139: // break;
1.1.1.29 root 17140: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
17141: sio_write(3, addr, val);
17142: break;
1.1.1.25 root 17143: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
17144: sio_write(1, addr, val);
17145: break;
17146: case 0x378: case 0x379: case 0x37a:
17147: pio_write(0, addr, val);
17148: break;
1.1.1.29 root 17149: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
17150: sio_write(2, addr, val);
17151: break;
1.1.1.25 root 17152: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
17153: sio_write(0, addr, val);
17154: break;
1.1 root 17155: default:
1.1.1.33 root 17156: // fatalerror("unknown outb %4x,%2x\n", addr, val);
1.1 root 17157: break;
17158: }
17159: }
17160:
17161: void write_io_word(offs_t addr, UINT16 val)
17162: {
17163: write_io_byte(addr + 0, (val >> 0) & 0xff);
17164: write_io_byte(addr + 1, (val >> 8) & 0xff);
17165: }
17166:
1.1.1.33 root 17167: #ifdef USE_DEBUGGER
17168: void debugger_write_io_word(offs_t addr, UINT16 val)
17169: {
17170: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
17171: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
17172: }
17173: #endif
17174:
1.1 root 17175: void write_io_dword(offs_t addr, UINT32 val)
17176: {
17177: write_io_byte(addr + 0, (val >> 0) & 0xff);
17178: write_io_byte(addr + 1, (val >> 8) & 0xff);
17179: write_io_byte(addr + 2, (val >> 16) & 0xff);
17180: write_io_byte(addr + 3, (val >> 24) & 0xff);
17181: }
1.1.1.33 root 17182:
17183: #ifdef USE_DEBUGGER
17184: void debugger_write_io_dword(offs_t addr, UINT32 val)
17185: {
17186: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
17187: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
17188: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
17189: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
17190: }
17191: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.