|
|
1.1 root 1: /*
2: MS-DOS Player for Win32 console
3:
4: Author : Takeda.Toshiya
5: Date : 2009.11.09-
6: */
7:
8: #include "msdos.h"
9:
1.1.1.28 root 10: void exit_handler();
11:
1.1 root 12: #define fatalerror(...) { \
13: fprintf(stderr, __VA_ARGS__); \
1.1.1.28 root 14: exit_handler(); \
1.1 root 15: exit(1); \
16: }
17: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
1.1.1.22 root 18: #define nolog(...)
19:
1.1.1.33 root 20: //#define ENABLE_DEBUG_LOG
21: #ifdef ENABLE_DEBUG_LOG
1.1.1.22 root 22: #define EXPORT_DEBUG_TO_FILE
23: #define ENABLE_DEBUG_SYSCALL
24: #define ENABLE_DEBUG_UNIMPLEMENTED
1.1.1.25 root 25: #define ENABLE_DEBUG_IOPORT
1.1.1.22 root 26:
27: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 28: FILE* fp_debug_log = NULL;
1.1.1.22 root 29: #else
1.1.1.33 root 30: #define fp_debug_log stderr
1.1.1.22 root 31: #endif
32: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
33: #define unimplemented_10h fatalerror
1.1.1.42 root 34: #define unimplemented_13h fatalerror
1.1.1.25 root 35: #define unimplemented_14h fatalerror
1.1.1.22 root 36: #define unimplemented_15h fatalerror
37: #define unimplemented_16h fatalerror
1.1.1.37 root 38: #define unimplemented_17h fatalerror
1.1.1.22 root 39: #define unimplemented_1ah fatalerror
40: #define unimplemented_21h fatalerror
41: #define unimplemented_2fh fatalerror
1.1.1.24 root 42: #define unimplemented_33h fatalerror
1.1.1.22 root 43: #define unimplemented_67h fatalerror
44: #define unimplemented_xms fatalerror
45: #endif
46: #endif
47: #ifndef unimplemented_10h
48: #define unimplemented_10h nolog
49: #endif
1.1.1.42 root 50: #ifndef unimplemented_13h
51: #define unimplemented_13h nolog
52: #endif
1.1.1.25 root 53: #ifndef unimplemented_14h
54: #define unimplemented_14h nolog
55: #endif
1.1.1.22 root 56: #ifndef unimplemented_15h
57: #define unimplemented_15h nolog
58: #endif
59: #ifndef unimplemented_16h
60: #define unimplemented_16h nolog
61: #endif
1.1.1.37 root 62: #ifndef unimplemented_17h
63: #define unimplemented_17h nolog
64: #endif
1.1.1.22 root 65: #ifndef unimplemented_1ah
66: #define unimplemented_1ah nolog
67: #endif
68: #ifndef unimplemented_21h
69: #define unimplemented_21h nolog
70: #endif
71: #ifndef unimplemented_2fh
72: #define unimplemented_2fh nolog
73: #endif
1.1.1.24 root 74: #ifndef unimplemented_33h
75: #define unimplemented_33h nolog
76: #endif
1.1.1.22 root 77: #ifndef unimplemented_67h
78: #define unimplemented_67h nolog
79: #endif
80: #ifndef unimplemented_xms
81: #define unimplemented_xms nolog
82: #endif
83:
1.1.1.32 root 84: #define array_length(array) (sizeof(array) / sizeof(array[0]))
1.1.1.22 root 85: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
86: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
87: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 88:
1.1.1.12 root 89: #if defined(__MINGW32__)
90: extern "C" int _CRT_glob = 0;
91: #endif
92:
93: /*
94: kludge for "more-standardized" C++
95: */
96: #if !defined(_MSC_VER)
97: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
98: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
99: #define min(a,b) kludge_min(a,b)
100: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 101: #elif _MSC_VER >= 1400
102: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
103: {
104: }
105: #endif
106:
1.1.1.35 root 107: #define USE_VRAM_THREAD
1.1.1.14 root 108:
1.1.1.35 root 109: #ifdef USE_VRAM_THREAD
1.1.1.14 root 110: static CRITICAL_SECTION vram_crit_sect;
111: #else
112: #define vram_flush()
1.1.1.12 root 113: #endif
114:
1.1.1.14 root 115: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
116: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
117:
118: void change_console_size(int width, int height);
119: void clear_scr_buffer(WORD attr);
120:
121: static UINT32 vram_length_char = 0, vram_length_attr = 0;
122: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
123: static COORD vram_coord_char, vram_coord_attr;
124:
1.1.1.28 root 125: char temp_file_path[MAX_PATH];
126: bool temp_file_created = false;
127:
1.1.1.14 root 128: bool ignore_illegal_insn = false;
129: bool limit_max_memory = false;
130: bool no_windows = false;
131: bool stay_busy = false;
1.1.1.19 root 132: bool support_ems = false;
133: #ifdef SUPPORT_XMS
134: bool support_xms = false;
135: #endif
1.1.1.29 root 136: int sio_port_number[4] = {0, 0, 0, 0};
1.1.1.14 root 137:
138: BOOL is_vista_or_later;
139:
1.1.1.35 root 140: #define UPDATE_OPS 16384
141: #define REQUEST_HARDWRE_UPDATE() { \
142: update_ops = UPDATE_OPS - 1; \
143: }
144: UINT32 update_ops = 0;
145: UINT32 idle_ops = 0;
146:
1.1.1.14 root 147: inline void maybe_idle()
148: {
149: // if it appears to be in a tight loop, assume waiting for input
150: // allow for one updated video character, for a spinning cursor
1.1.1.35 root 151: if(!stay_busy && idle_ops < 1024 && vram_length_char <= 1 && vram_length_attr <= 1) {
1.1.1.14 root 152: Sleep(10);
1.1.1.35 root 153: REQUEST_HARDWRE_UPDATE();
1.1.1.14 root 154: }
1.1.1.35 root 155: idle_ops = 0;
1.1.1.14 root 156: }
1.1.1.12 root 157:
1.1 root 158: /* ----------------------------------------------------------------------------
1.1.1.3 root 159: MAME i86/i386
1.1 root 160: ---------------------------------------------------------------------------- */
161:
1.1.1.10 root 162: #ifndef __BIG_ENDIAN__
1.1 root 163: #define LSB_FIRST
1.1.1.10 root 164: #endif
1.1 root 165:
166: #ifndef INLINE
167: #define INLINE inline
168: #endif
169: #define U64(v) UINT64(v)
170:
171: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
172: #define logerror(...)
173: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
174: #define popmessage(...)
175:
176: /*****************************************************************************/
1.1.1.10 root 177: /* src/emu/devcpu.h */
178:
179: // CPU interface functions
180: #define CPU_INIT_NAME(name) cpu_init_##name
181: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
182: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
183:
184: #define CPU_RESET_NAME(name) cpu_reset_##name
185: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
186: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
187:
188: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
189: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
190: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
191:
192: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
193: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
194: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
195:
196: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
197: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
198: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
199:
1.1.1.14 root 200: #define CPU_MODEL_STR(name) #name
201: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
202:
1.1.1.10 root 203: /*****************************************************************************/
204: /* src/emu/didisasm.h */
205:
206: // Disassembler constants
207: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
208: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
209: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
210: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
211: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
212: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
213:
214: /*****************************************************************************/
1.1 root 215: /* src/emu/diexec.h */
216:
217: // I/O line states
218: enum line_state
219: {
220: CLEAR_LINE = 0, // clear (a fired or held) line
221: ASSERT_LINE, // assert an interrupt immediately
222: HOLD_LINE, // hold interrupt line until acknowledged
223: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
224: };
225:
226: // I/O line definitions
227: enum
228: {
229: INPUT_LINE_IRQ = 0,
230: INPUT_LINE_NMI
231: };
232:
233: /*****************************************************************************/
1.1.1.10 root 234: /* src/emu/dimemory.h */
1.1 root 235:
1.1.1.10 root 236: // Translation intentions
237: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
238: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
239: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
240:
241: const int TRANSLATE_READ = 0; // translate for read
242: const int TRANSLATE_WRITE = 1; // translate for write
243: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
244: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
245: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
246: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
247: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
248: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
249: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 250:
1.1.1.10 root 251: /*****************************************************************************/
252: /* src/emu/emucore.h */
1.1 root 253:
1.1.1.10 root 254: // constants for expression endianness
255: enum endianness_t
256: {
257: ENDIANNESS_LITTLE,
258: ENDIANNESS_BIG
259: };
1.1 root 260:
1.1.1.10 root 261: // declare native endianness to be one or the other
262: #ifdef LSB_FIRST
263: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
264: #else
265: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
266: #endif
267:
268: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
269: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
270:
271: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
272: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
273:
274: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
275: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 276:
277: /*****************************************************************************/
278: /* src/emu/memory.h */
279:
1.1.1.10 root 280: // address spaces
281: enum address_spacenum
282: {
283: AS_0, // first address space
284: AS_1, // second address space
285: AS_2, // third address space
286: AS_3, // fourth address space
287: ADDRESS_SPACES, // maximum number of address spaces
288:
289: // alternate address space names for common use
290: AS_PROGRAM = AS_0, // program address space
291: AS_DATA = AS_1, // data address space
292: AS_IO = AS_2 // I/O address space
293: };
294:
1.1 root 295: // offsets and addresses are 32-bit (for now...)
1.1.1.30 root 296: //typedef UINT32 offs_t;
1.1 root 297:
298: // read accessors
299: UINT8 read_byte(offs_t byteaddress)
1.1.1.33 root 300: #ifdef USE_DEBUGGER
301: {
302: if(now_debugging) {
303: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
304: if(rd_break_point.table[i].status == 1) {
305: if(byteaddress == rd_break_point.table[i].addr) {
306: rd_break_point.hit = i + 1;
307: now_suspended = true;
308: break;
309: }
310: }
311: }
312: }
313: return(debugger_read_byte(byteaddress));
314: }
315: UINT8 debugger_read_byte(offs_t byteaddress)
316: #endif
1.1 root 317: {
1.1.1.4 root 318: #if defined(HAS_I386)
1.1 root 319: if(byteaddress < MAX_MEM) {
320: return mem[byteaddress];
1.1.1.3 root 321: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
322: // return read_byte(byteaddress & 0xfffff);
1.1 root 323: }
324: return 0;
1.1.1.4 root 325: #else
326: return mem[byteaddress];
327: #endif
1.1 root 328: }
329:
330: UINT16 read_word(offs_t byteaddress)
1.1.1.33 root 331: #ifdef USE_DEBUGGER
332: {
333: if(now_debugging) {
334: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
335: if(rd_break_point.table[i].status == 1) {
336: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 2) {
337: rd_break_point.hit = i + 1;
338: now_suspended = true;
339: break;
340: }
341: }
342: }
343: }
344: return(debugger_read_word(byteaddress));
345: }
346: UINT16 debugger_read_word(offs_t byteaddress)
347: #endif
1.1 root 348: {
1.1.1.14 root 349: if(byteaddress == 0x41c) {
350: // pointer to first free slot in keyboard buffer
351: // XXX: the buffer itself doesn't actually exist in DOS memory
1.1.1.35 root 352: if(key_buf_char != NULL && key_buf_scan != NULL) {
353: #ifdef USE_SERVICE_THREAD
354: EnterCriticalSection(&key_buf_crit_sect);
355: #endif
1.1.1.41 root 356: int count = min(key_buf_char->count(), 15);
357: // write to top of key buffer
358: for(int i = 0; i < count; i++) {
359: mem[0x41e + 2 * i + 0] = key_buf_char->read_not_remove(i);
360: mem[0x41e + 2 * i + 1] = key_buf_scan->read_not_remove(i);
361: }
1.1.1.35 root 362: #ifdef USE_SERVICE_THREAD
363: LeaveCriticalSection(&key_buf_crit_sect);
364: #endif
365: if(count == 0) {
1.1.1.32 root 366: maybe_idle();
367: }
1.1.1.41 root 368: return (UINT16)(0x1e + 2 * count);
1.1.1.14 root 369: }
1.1.1.41 root 370: return 0x1e;
1.1.1.14 root 371: }
1.1.1.4 root 372: #if defined(HAS_I386)
1.1 root 373: if(byteaddress < MAX_MEM - 1) {
374: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 375: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
376: // return read_word(byteaddress & 0xfffff);
1.1 root 377: }
378: return 0;
1.1.1.4 root 379: #else
380: return *(UINT16 *)(mem + byteaddress);
381: #endif
1.1 root 382: }
383:
384: UINT32 read_dword(offs_t byteaddress)
1.1.1.33 root 385: #ifdef USE_DEBUGGER
386: {
387: if(now_debugging) {
388: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
389: if(rd_break_point.table[i].status == 1) {
390: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 4) {
391: rd_break_point.hit = i + 1;
392: now_suspended = true;
393: break;
394: }
395: }
396: }
397: }
398: return(debugger_read_dword(byteaddress));
399: }
400: UINT32 debugger_read_dword(offs_t byteaddress)
401: #endif
1.1 root 402: {
1.1.1.4 root 403: #if defined(HAS_I386)
1.1 root 404: if(byteaddress < MAX_MEM - 3) {
405: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 406: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
407: // return read_dword(byteaddress & 0xfffff);
1.1 root 408: }
409: return 0;
1.1.1.4 root 410: #else
411: return *(UINT32 *)(mem + byteaddress);
412: #endif
1.1 root 413: }
414:
415: // write accessors
1.1.1.35 root 416: #ifdef USE_VRAM_THREAD
1.1.1.14 root 417: void vram_flush_char()
418: {
419: if(vram_length_char != 0) {
420: DWORD num;
1.1.1.23 root 421: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 422: vram_length_char = vram_last_length_char = 0;
423: }
424: }
425:
426: void vram_flush_attr()
427: {
428: if(vram_length_attr != 0) {
429: DWORD num;
1.1.1.23 root 430: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 431: vram_length_attr = vram_last_length_attr = 0;
432: }
433: }
434:
435: void vram_flush()
436: {
437: if(vram_length_char != 0 || vram_length_attr != 0) {
438: EnterCriticalSection(&vram_crit_sect);
439: vram_flush_char();
440: vram_flush_attr();
441: LeaveCriticalSection(&vram_crit_sect);
442: }
443: }
444: #endif
445:
446: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 447: {
1.1.1.35 root 448: #ifdef USE_VRAM_THREAD
1.1.1.14 root 449: static offs_t first_offset_char, last_offset_char;
450:
451: if(vram_length_char != 0) {
452: if(offset <= last_offset_char && offset >= first_offset_char) {
453: scr_char[(offset - first_offset_char) >> 1] = data;
454: return;
455: }
456: if(offset != last_offset_char + 2) {
457: vram_flush_char();
458: }
459: }
460: if(vram_length_char == 0) {
461: first_offset_char = offset;
462: vram_coord_char.X = (offset >> 1) % scr_width;
463: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
464: }
465: scr_char[vram_length_char++] = data;
466: last_offset_char = offset;
467: #else
1.1.1.8 root 468: COORD co;
469: DWORD num;
470:
1.1.1.14 root 471: co.X = (offset >> 1) % scr_width;
472: co.Y = (offset >> 1) / scr_width;
473: scr_char[0] = data;
1.1.1.23 root 474: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 475: #endif
476: }
477:
478: void write_text_vram_attr(offs_t offset, UINT8 data)
479: {
1.1.1.35 root 480: #ifdef USE_VRAM_THREAD
1.1.1.14 root 481: static offs_t first_offset_attr, last_offset_attr;
482:
483: if(vram_length_attr != 0) {
484: if(offset <= last_offset_attr && offset >= first_offset_attr) {
485: scr_attr[(offset - first_offset_attr) >> 1] = data;
486: return;
487: }
488: if(offset != last_offset_attr + 2) {
489: vram_flush_attr();
490: }
491: }
492: if(vram_length_attr == 0) {
493: first_offset_attr = offset;
494: vram_coord_attr.X = (offset >> 1) % scr_width;
495: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
496: }
497: scr_attr[vram_length_attr++] = data;
498: last_offset_attr = offset;
499: #else
500: COORD co;
501: DWORD num;
1.1.1.8 root 502:
1.1.1.14 root 503: co.X = (offset >> 1) % scr_width;
504: co.Y = (offset >> 1) / scr_width;
505: scr_attr[0] = data;
1.1.1.23 root 506: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 507: #endif
508: }
509:
510: void write_text_vram_byte(offs_t offset, UINT8 data)
511: {
1.1.1.35 root 512: #ifdef USE_VRAM_THREAD
1.1.1.14 root 513: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 514: #endif
1.1.1.8 root 515: if(offset & 1) {
1.1.1.14 root 516: write_text_vram_attr(offset, data);
1.1.1.8 root 517: } else {
1.1.1.14 root 518: write_text_vram_char(offset, data);
1.1.1.8 root 519: }
1.1.1.35 root 520: #ifdef USE_VRAM_THREAD
1.1.1.14 root 521: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 522: #endif
1.1.1.8 root 523: }
524:
525: void write_text_vram_word(offs_t offset, UINT16 data)
526: {
1.1.1.35 root 527: #ifdef USE_VRAM_THREAD
1.1.1.14 root 528: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 529: #endif
1.1.1.8 root 530: if(offset & 1) {
1.1.1.14 root 531: write_text_vram_attr(offset , (data ) & 0xff);
532: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 533: } else {
1.1.1.14 root 534: write_text_vram_char(offset , (data ) & 0xff);
535: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 536: }
1.1.1.35 root 537: #ifdef USE_VRAM_THREAD
1.1.1.14 root 538: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 539: #endif
1.1.1.8 root 540: }
541:
542: void write_text_vram_dword(offs_t offset, UINT32 data)
543: {
1.1.1.35 root 544: #ifdef USE_VRAM_THREAD
1.1.1.14 root 545: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 546: #endif
1.1.1.8 root 547: if(offset & 1) {
1.1.1.14 root 548: write_text_vram_attr(offset , (data ) & 0xff);
549: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
550: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
551: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
552: } else {
553: write_text_vram_char(offset , (data ) & 0xff);
554: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
555: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
556: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 557: }
1.1.1.35 root 558: #ifdef USE_VRAM_THREAD
1.1.1.14 root 559: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 560: #endif
1.1.1.8 root 561: }
562:
1.1 root 563: void write_byte(offs_t byteaddress, UINT8 data)
1.1.1.33 root 564: #ifdef USE_DEBUGGER
565: {
566: if(now_debugging) {
567: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
568: if(wr_break_point.table[i].status == 1) {
569: if(byteaddress == wr_break_point.table[i].addr) {
570: wr_break_point.hit = i + 1;
571: now_suspended = true;
572: break;
573: }
574: }
575: }
576: }
577: debugger_write_byte(byteaddress, data);
578: }
579: void debugger_write_byte(offs_t byteaddress, UINT8 data)
580: #endif
1.1 root 581: {
1.1.1.8 root 582: if(byteaddress < MEMORY_END) {
1.1.1.3 root 583: mem[byteaddress] = data;
1.1.1.8 root 584: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 585: if(!restore_console_on_exit) {
586: change_console_size(scr_width, scr_height);
1.1.1.12 root 587: }
1.1.1.8 root 588: write_text_vram_byte(byteaddress - text_vram_top_address, data);
589: mem[byteaddress] = data;
590: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
591: if(int_10h_feh_called && !int_10h_ffh_called) {
592: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 593: }
594: mem[byteaddress] = data;
1.1.1.4 root 595: #if defined(HAS_I386)
1.1.1.3 root 596: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 597: #else
598: } else {
599: #endif
1.1.1.3 root 600: mem[byteaddress] = data;
1.1 root 601: }
602: }
603:
604: void write_word(offs_t byteaddress, UINT16 data)
1.1.1.33 root 605: #ifdef USE_DEBUGGER
606: {
607: if(now_debugging) {
608: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
609: if(wr_break_point.table[i].status == 1) {
610: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 2) {
611: wr_break_point.hit = i + 1;
612: now_suspended = true;
613: break;
614: }
615: }
616: }
617: }
618: debugger_write_word(byteaddress, data);
619: }
620: void debugger_write_word(offs_t byteaddress, UINT16 data)
621: #endif
1.1 root 622: {
1.1.1.8 root 623: if(byteaddress < MEMORY_END) {
1.1.1.14 root 624: if(byteaddress == 0x450 + mem[0x462] * 2) {
625: COORD co;
626: co.X = data & 0xff;
627: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 628: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 629: }
1.1.1.3 root 630: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 631: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 632: if(!restore_console_on_exit) {
633: change_console_size(scr_width, scr_height);
1.1.1.12 root 634: }
1.1.1.8 root 635: write_text_vram_word(byteaddress - text_vram_top_address, data);
636: *(UINT16 *)(mem + byteaddress) = data;
637: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
638: if(int_10h_feh_called && !int_10h_ffh_called) {
639: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 640: }
641: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 642: #if defined(HAS_I386)
1.1.1.3 root 643: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 644: #else
645: } else {
646: #endif
1.1.1.3 root 647: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 648: }
649: }
650:
651: void write_dword(offs_t byteaddress, UINT32 data)
1.1.1.33 root 652: #ifdef USE_DEBUGGER
653: {
654: if(now_debugging) {
655: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
656: if(wr_break_point.table[i].status == 1) {
657: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 4) {
658: wr_break_point.hit = i + 1;
659: now_suspended = true;
660: break;
661: }
662: }
663: }
664: }
665: debugger_write_dword(byteaddress, data);
666: }
667: void debugger_write_dword(offs_t byteaddress, UINT32 data)
668: #endif
1.1 root 669: {
1.1.1.8 root 670: if(byteaddress < MEMORY_END) {
1.1.1.3 root 671: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 672: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 673: if(!restore_console_on_exit) {
674: change_console_size(scr_width, scr_height);
1.1.1.12 root 675: }
1.1.1.8 root 676: write_text_vram_dword(byteaddress - text_vram_top_address, data);
677: *(UINT32 *)(mem + byteaddress) = data;
678: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
679: if(int_10h_feh_called && !int_10h_ffh_called) {
680: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 681: }
682: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 683: #if defined(HAS_I386)
1.1.1.3 root 684: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 685: #else
686: } else {
687: #endif
1.1.1.3 root 688: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 689: }
690: }
691:
692: #define read_decrypted_byte read_byte
693: #define read_decrypted_word read_word
694: #define read_decrypted_dword read_dword
695:
1.1.1.3 root 696: #define read_raw_byte read_byte
697: #define write_raw_byte write_byte
698:
699: #define read_word_unaligned read_word
700: #define write_word_unaligned write_word
701:
702: #define read_io_word_unaligned read_io_word
703: #define write_io_word_unaligned write_io_word
704:
1.1 root 705: UINT8 read_io_byte(offs_t byteaddress);
706: UINT16 read_io_word(offs_t byteaddress);
707: UINT32 read_io_dword(offs_t byteaddress);
708:
709: void write_io_byte(offs_t byteaddress, UINT8 data);
710: void write_io_word(offs_t byteaddress, UINT16 data);
711: void write_io_dword(offs_t byteaddress, UINT32 data);
712:
713: /*****************************************************************************/
714: /* src/osd/osdcomm.h */
715:
716: /* Highly useful macro for compile-time knowledge of an array size */
717: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
718:
1.1.1.3 root 719: #if defined(HAS_I386)
1.1.1.10 root 720: static CPU_TRANSLATE(i386);
721: #include "mame/lib/softfloat/softfloat.c"
722: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 723: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 724: #elif defined(HAS_I286)
1.1.1.10 root 725: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 726: #else
1.1.1.10 root 727: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 728: #endif
1.1.1.33 root 729: #ifdef USE_DEBUGGER
1.1.1.10 root 730: #include "mame/emu/cpu/i386/i386dasm.c"
1.1 root 731: #endif
732:
1.1.1.3 root 733: #if defined(HAS_I386)
734: #define SREG(x) m_sreg[x].selector
735: #define SREG_BASE(x) m_sreg[x].base
736: int cpu_type, cpu_step;
737: #else
738: #define REG8(x) m_regs.b[x]
739: #define REG16(x) m_regs.w[x]
740: #define SREG(x) m_sregs[x]
741: #define SREG_BASE(x) m_base[x]
1.1.1.33 root 742: #define m_eip (m_pc - m_base[CS])
1.1.1.3 root 743: #define m_CF m_CarryVal
744: #define m_a20_mask AMASK
745: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
746: #if defined(HAS_I286)
747: #define i386_set_a20_line(x) i80286_set_a20_line(x)
748: #else
749: #define i386_set_a20_line(x)
750: #endif
751: #define i386_set_irq_line(x, y) set_irq_line(x, y)
752: #endif
1.1 root 753:
754: void i386_jmp_far(UINT16 selector, UINT32 address)
755: {
1.1.1.3 root 756: #if defined(HAS_I386)
1.1 root 757: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 758: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 759: } else {
1.1.1.3 root 760: SREG(CS) = selector;
761: m_performed_intersegment_jump = 1;
762: i386_load_segment_descriptor(CS);
763: m_eip = address;
764: CHANGE_PC(m_eip);
1.1 root 765: }
1.1.1.3 root 766: #elif defined(HAS_I286)
767: i80286_code_descriptor(selector, address, 1);
768: #else
769: SREG(CS) = selector;
770: i386_load_segment_descriptor(CS);
771: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
772: #endif
1.1 root 773: }
774:
1.1.1.24 root 775: void i386_call_far(UINT16 selector, UINT32 address)
776: {
777: #if defined(HAS_I386)
778: if(PROTECTED_MODE && !V8086_MODE) {
779: i386_protected_mode_call(selector, address, 1, m_operand_size);
780: } else {
781: PUSH16(SREG(CS));
782: PUSH16(m_eip);
783: SREG(CS) = selector;
784: m_performed_intersegment_jump = 1;
785: i386_load_segment_descriptor(CS);
786: m_eip = address;
787: CHANGE_PC(m_eip);
788: }
789: #else
790: UINT16 ip = m_pc - SREG_BASE(CS);
791: UINT16 cs = SREG(CS);
792: #if defined(HAS_I286)
793: i80286_code_descriptor(selector, address, 2);
794: #else
795: SREG(CS) = selector;
796: i386_load_segment_descriptor(CS);
797: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
798: #endif
799: PUSH(cs);
800: PUSH(ip);
801: CHANGE_PC(m_pc);
802: #endif
803: }
1.1.1.49! root 804:
! 805: void i386_push16(UINT16 value)
! 806: {
! 807: #if defined(HAS_I386)
! 808: PUSH16(value);
! 809: #else
! 810: PUSH(value);
1.1.1.35 root 811: #endif
1.1.1.49! root 812: }
! 813:
! 814: UINT16 i386_pop16()
! 815: {
! 816: #if defined(HAS_I386)
! 817: return POP16();
! 818: #else
! 819: UINT16 value;
! 820: POP(value);
! 821: return value;
! 822: #endif
! 823: }
1.1.1.24 root 824:
1.1.1.29 root 825: UINT16 i386_read_stack()
826: {
827: #if defined(HAS_I386)
828: UINT32 ea, new_esp;
829: if( STACK_32BIT ) {
830: new_esp = REG32(ESP) + 2;
831: ea = i386_translate(SS, new_esp - 2, 0);
832: } else {
833: new_esp = REG16(SP) + 2;
834: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
835: }
836: return READ16(ea);
837: #else
838: UINT16 sp = m_regs.w[SP] + 2;
839: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
840: #endif
841: }
842:
1.1 root 843: /* ----------------------------------------------------------------------------
1.1.1.33 root 844: debugger
845: ---------------------------------------------------------------------------- */
846:
847: #ifdef USE_DEBUGGER
848: #define TELNET_BLUE 0x0004 // text color contains blue.
849: #define TELNET_GREEN 0x0002 // text color contains green.
850: #define TELNET_RED 0x0001 // text color contains red.
851: #define TELNET_INTENSITY 0x0008 // text color is intensified.
852:
853: int svr_socket = 0;
854: int cli_socket = 0;
855:
856: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error);
857:
858: void debugger_init()
859: {
860: now_debugging = false;
861: now_going = false;
862: now_suspended = false;
863: force_suspend = false;
864:
865: memset(&break_point, 0, sizeof(break_point_t));
866: memset(&rd_break_point, 0, sizeof(break_point_t));
867: memset(&wr_break_point, 0, sizeof(break_point_t));
868: memset(&in_break_point, 0, sizeof(break_point_t));
869: memset(&out_break_point, 0, sizeof(break_point_t));
870: memset(&int_break_point, 0, sizeof(int_break_point_t));
871: }
872:
1.1.1.45 root 873: void telnet_send(const char *string)
1.1.1.33 root 874: {
875: char buffer[8192], *ptr;
876: strcpy(buffer, string);
877: while((ptr = strstr(buffer, "\n")) != NULL) {
878: char tmp[8192];
879: *ptr = '\0';
880: sprintf(tmp, "%s\033E%s", buffer, ptr + 1);
881: strcpy(buffer, tmp);
882: }
883:
884: int len = strlen(buffer), res;
885: ptr = buffer;
886: while(len > 0) {
887: if((res = send(cli_socket, ptr, len, 0)) > 0) {
888: len -= res;
889: ptr += res;
890: }
891: }
892: }
893:
894: void telnet_command(const char *format, ...)
895: {
896: char buffer[1024];
897: va_list ap;
898: va_start(ap, format);
899: vsprintf(buffer, format, ap);
900: va_end(ap);
901:
902: telnet_send(buffer);
903: }
904:
905: void telnet_printf(const char *format, ...)
906: {
907: char buffer[1024];
908: va_list ap;
909: va_start(ap, format);
910: vsprintf(buffer, format, ap);
911: va_end(ap);
912:
913: if(fp_debugger != NULL) {
914: fprintf(fp_debugger, "%s", buffer);
915: }
916: telnet_send(buffer);
917: }
918:
919: bool telnet_gets(char *str, int n)
920: {
921: char buffer[1024];
922: int ptr = 0;
923:
924: telnet_command("\033[12l"); // local echo on
925: telnet_command("\033[2l"); // key unlock
926:
927: while(!m_halted) {
928: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
929:
930: if(len > 0 && buffer[0] != 0xff) {
931: for(int i = 0; i < len; i++) {
932: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
933: str[ptr] = 0;
934: telnet_command("\033[2h"); // key lock
935: telnet_command("\033[12h"); // local echo off
936: return(!m_halted);
937: } else if(buffer[i] == 0x08) {
938: if(ptr > 0) {
939: telnet_command("\033[0K"); // erase from cursor position
940: ptr--;
941: } else {
942: telnet_command("\033[1C"); // move cursor forward
943: }
944: } else if(ptr < n - 1) {
1.1.1.37 root 945: if(buffer[i] >= 0x20 && buffer[i] <= 0x7e) {
1.1.1.33 root 946: str[ptr++] = buffer[i];
947: }
948: } else {
949: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position
950: }
951: }
952: } else if(len == -1) {
953: if(WSAGetLastError() != WSAEWOULDBLOCK) {
954: return(false);
955: }
956: } else if(len == 0) {
957: return(false);
958: }
959: Sleep(10);
960: }
961: return(!m_halted);
962: }
963:
964: bool telnet_kbhit()
965: {
966: char buffer[1024];
967:
968: if(!m_halted) {
969: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
970:
971: if(len > 0) {
972: for(int i = 0; i < len; i++) {
973: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
974: return(true);
975: }
976: }
977: } else if(len == 0) {
978: return(true); // disconnected
979: }
980: }
981: return(false);
982: }
983:
984: bool telnet_disconnected()
985: {
986: char buffer[1024];
987: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
988:
989: if(len == 0) {
990: return(true);
991: } else if(len == -1) {
992: if(WSAGetLastError() != WSAEWOULDBLOCK) {
993: return(true);
994: }
995: }
996: return(false);
997: }
998:
999: void telnet_set_color(int color)
1000: {
1001: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7));
1002: }
1003:
1004: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip)
1005: {
1006: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1));
1007: UINT8 ops[16];
1008: for(int i = 0; i < 16; i++) {
1009: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK);
1010: }
1011: UINT8 *oprom = ops;
1012:
1013: #if defined(HAS_I386)
1014: if(m_operand_size) {
1015: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK);
1016: } else
1017: #endif
1018: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK);
1019: }
1020:
1021: void debugger_regs_info(char *buffer)
1022: {
1023: #if defined(HAS_I386)
1024: UINT32 flags = get_flags();
1025: #else
1026: UINT32 flags = CompressFlags();
1027: #endif
1028: #if defined(HAS_I386)
1029: if(m_operand_size) {
1030: 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",
1031: 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),
1032: PROTECTED_MODE ? "PE" : "--",
1033: (flags & 0x40000) ? 'A' : '-',
1034: (flags & 0x20000) ? 'V' : '-',
1035: (flags & 0x10000) ? 'R' : '-',
1036: (flags & 0x04000) ? 'N' : '-',
1037: (flags & 0x02000) ? '1' : '0',
1038: (flags & 0x01000) ? '1' : '0',
1039: (flags & 0x00800) ? 'O' : '-',
1040: (flags & 0x00400) ? 'D' : '-',
1041: (flags & 0x00200) ? 'I' : '-',
1042: (flags & 0x00100) ? 'T' : '-',
1043: (flags & 0x00080) ? 'S' : '-',
1044: (flags & 0x00040) ? 'Z' : '-',
1045: (flags & 0x00010) ? 'A' : '-',
1046: (flags & 0x00004) ? 'P' : '-',
1047: (flags & 0x00001) ? 'C' : '-');
1048: } else {
1049: #endif
1050: 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",
1051: 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),
1052: #if defined(HAS_I386)
1053: PROTECTED_MODE ? "PE" : "--",
1054: #else
1055: "--",
1056: #endif
1057: (flags & 0x40000) ? 'A' : '-',
1058: (flags & 0x20000) ? 'V' : '-',
1059: (flags & 0x10000) ? 'R' : '-',
1060: (flags & 0x04000) ? 'N' : '-',
1061: (flags & 0x02000) ? '1' : '0',
1062: (flags & 0x01000) ? '1' : '0',
1063: (flags & 0x00800) ? 'O' : '-',
1064: (flags & 0x00400) ? 'D' : '-',
1065: (flags & 0x00200) ? 'I' : '-',
1066: (flags & 0x00100) ? 'T' : '-',
1067: (flags & 0x00080) ? 'S' : '-',
1068: (flags & 0x00040) ? 'Z' : '-',
1069: (flags & 0x00010) ? 'A' : '-',
1070: (flags & 0x00004) ? 'P' : '-',
1071: (flags & 0x00001) ? 'C' : '-');
1072: #if defined(HAS_I386)
1073: }
1074: #endif
1075: }
1076:
1077: void debugger_process_info(char *buffer)
1078: {
1079: UINT16 psp_seg = current_psp;
1080: process_t *process;
1081: bool check[0x10000] = {0};
1082:
1083: buffer[0] = '\0';
1084:
1085: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) {
1086: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1087: char *file = process->module_path, *s;
1088: char tmp[8192];
1089:
1090: while((s = strstr(file, "\\")) != NULL) {
1091: file = s + 1;
1092: }
1093: 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));
1094: strcat(tmp, buffer);
1095: strcpy(buffer, tmp);
1096:
1097: check[psp_seg] = true;
1098: psp_seg = psp->parent_psp;
1099: }
1100: }
1101:
1102: UINT32 debugger_get_val(const char *str)
1103: {
1104: char tmp[1024];
1105:
1106: if(str == NULL || strlen(str) == 0) {
1107: return(0);
1108: }
1109: strcpy(tmp, str);
1110:
1111: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') {
1112: // ank
1113: return(tmp[1] & 0xff);
1114: } else if(tmp[0] == '%') {
1115: // decimal
1116: return(strtoul(tmp + 1, NULL, 10));
1117: }
1118: return(strtoul(tmp, NULL, 16));
1119: }
1120:
1121: UINT32 debugger_get_seg(const char *str, UINT32 val)
1122: {
1123: char tmp[1024], *s;
1124:
1125: if(str == NULL || strlen(str) == 0) {
1126: return(val);
1127: }
1128: strcpy(tmp, str);
1129:
1130: if((s = strstr(tmp, ":")) != NULL) {
1131: // 0000:0000
1132: *s = '\0';
1133: return(debugger_get_val(tmp));
1134: }
1135: return(val);
1136: }
1137:
1138: UINT32 debugger_get_ofs(const char *str)
1139: {
1140: char tmp[1024], *s;
1141:
1142: if(str == NULL || strlen(str) == 0) {
1143: return(0);
1144: }
1145: strcpy(tmp, str);
1146:
1147: if((s = strstr(tmp, ":")) != NULL) {
1148: // 0000:0000
1149: return(debugger_get_val(s + 1));
1150: }
1151: return(debugger_get_val(tmp));
1152: }
1153:
1154: void debugger_main()
1155: {
1156: telnet_command("\033[20h"); // cr-lf
1157:
1158: force_suspend = true;
1159: now_going = false;
1160: now_debugging = true;
1161: Sleep(100);
1162:
1163: if(!m_halted && !now_suspended) {
1164: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1165: telnet_printf("waiting until cpu is suspended...\n");
1166: }
1167: while(!m_halted && !now_suspended) {
1168: if(telnet_disconnected()) {
1169: break;
1170: }
1171: Sleep(10);
1172: }
1173:
1174: char buffer[8192];
1175:
1176: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1177: debugger_process_info(buffer);
1178: telnet_printf("%s", buffer);
1179: debugger_regs_info(buffer);
1180: telnet_printf("%s", buffer);
1181: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1182: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip);
1183: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1184: debugger_dasm(buffer, SREG(CS), m_eip);
1185: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1186: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1187:
1188: #define MAX_COMMAND_LEN 64
1189:
1190: char command[MAX_COMMAND_LEN + 1];
1191: char prev_command[MAX_COMMAND_LEN + 1] = {0};
1192:
1193: UINT32 data_seg = SREG(DS);
1194: UINT32 data_ofs = 0;
1195: UINT32 dasm_seg = SREG(CS);
1196: UINT32 dasm_ofs = m_eip;
1197:
1198: while(!m_halted) {
1199: telnet_printf("- ");
1200: command[0] = '\0';
1201:
1202: if(fi_debugger != NULL) {
1203: while(command[0] == '\0') {
1204: if(fgets(command, sizeof(command), fi_debugger) == NULL) {
1205: break;
1206: }
1207: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) {
1208: command[strlen(command) - 1] = '\0';
1209: }
1210: }
1211: if(command[0] != '\0') {
1212: telnet_command("%s\n", command);
1213: }
1214: }
1215: if(command[0] == '\0') {
1216: if(!telnet_gets(command, sizeof(command))) {
1217: break;
1218: }
1219: }
1220: if(command[0] == '\0') {
1221: strcpy(command, prev_command);
1222: } else {
1223: strcpy(prev_command, command);
1224: }
1225: if(fp_debugger != NULL) {
1226: fprintf(fp_debugger, "%s\n", command);
1227: }
1228:
1229: if(!m_halted && command[0] != 0) {
1230: char *params[32], *token = NULL;
1231: int num = 0;
1232:
1233: if((token = strtok(command, " ")) != NULL) {
1234: params[num++] = token;
1235: while(num < 32 && (token = strtok(NULL, " ")) != NULL) {
1236: params[num++] = token;
1237: }
1238: }
1239: if(stricmp(params[0], "D") == 0) {
1240: if(num <= 3) {
1241: if(num >= 2) {
1242: data_seg = debugger_get_seg(params[1], data_seg);
1243: data_ofs = debugger_get_ofs(params[1]);
1244: }
1245: UINT32 end_seg = data_seg;
1246: UINT32 end_ofs = data_ofs + 8 * 16 - 1;
1247: if(num == 3) {
1248: end_seg = debugger_get_seg(params[2], data_seg);
1249: end_ofs = debugger_get_ofs(params[2]);
1250: }
1251: UINT64 start_addr = (data_seg << 4) + data_ofs;
1252: UINT64 end_addr = (end_seg << 4) + end_ofs;
1.1.1.37 root 1253: // bool is_sjis = false;
1.1.1.33 root 1254:
1255: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) {
1256: if((addr & 0x0f) == 0) {
1257: if((data_ofs = addr - (data_seg << 4)) > 0xffff) {
1258: data_seg += 0x1000;
1259: data_ofs -= 0x10000;
1260: }
1261: telnet_printf("%06X:%04X ", data_seg, data_ofs);
1262: memset(buffer, 0, sizeof(buffer));
1263: }
1264: if(addr < start_addr || addr > end_addr) {
1265: telnet_printf(" ");
1266: buffer[addr & 0x0f] = ' ';
1267: } else {
1268: UINT8 data = debugger_read_byte(addr & ADDR_MASK);
1269: telnet_printf(" %02X", data);
1.1.1.37 root 1270: // if(is_sjis) {
1.1.1.33 root 1271: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1272: // is_sjis = false;
1.1.1.33 root 1273: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) {
1274: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1275: // is_sjis = true;
1.1.1.33 root 1276: // } else
1277: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) {
1278: buffer[addr & 0x0f] = data;
1279: } else {
1280: buffer[addr & 0x0f] = '.';
1281: }
1282: }
1283: if((addr & 0x0f) == 0x0f) {
1284: telnet_printf(" %s\n", buffer);
1285: }
1286: }
1287: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) {
1288: data_seg += 0x1000;
1289: data_ofs -= 0x10000;
1290: }
1291: prev_command[1] = '\0'; // remove parameters to dump continuously
1292: } else {
1293: telnet_printf("invalid parameter number\n");
1294: }
1295: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) {
1296: if(num >= 3) {
1297: UINT32 seg = debugger_get_seg(params[1], data_seg);
1298: UINT32 ofs = debugger_get_ofs(params[1]);
1299: for(int i = 2, j = 0; i < num; i++, j++) {
1300: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff);
1301: }
1302: } else {
1303: telnet_printf("invalid parameter number\n");
1304: }
1305: } else if(stricmp(params[0], "EW") == 0) {
1306: if(num >= 3) {
1307: UINT32 seg = debugger_get_seg(params[1], data_seg);
1308: UINT32 ofs = debugger_get_ofs(params[1]);
1309: for(int i = 2, j = 0; i < num; i++, j += 2) {
1310: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff);
1311: }
1312: } else {
1313: telnet_printf("invalid parameter number\n");
1314: }
1315: } else if(stricmp(params[0], "ED") == 0) {
1316: if(num >= 3) {
1317: UINT32 seg = debugger_get_seg(params[1], data_seg);
1318: UINT32 ofs = debugger_get_ofs(params[1]);
1319: for(int i = 2, j = 0; i < num; i++, j += 4) {
1320: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]));
1321: }
1322: } else {
1323: telnet_printf("invalid parameter number\n");
1324: }
1325: } else if(stricmp(params[0], "EA") == 0) {
1326: if(num >= 3) {
1327: UINT32 seg = debugger_get_seg(params[1], data_seg);
1328: UINT32 ofs = debugger_get_ofs(params[1]);
1329: strcpy(buffer, prev_command);
1330: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) {
1331: int len = strlen(token);
1332: for(int i = 0; i < len; i++) {
1333: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff);
1334: }
1335: } else {
1336: telnet_printf("invalid parameter\n");
1337: }
1338: } else {
1339: telnet_printf("invalid parameter number\n");
1340: }
1341: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) {
1342: if(num == 2) {
1343: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff);
1344: } else {
1345: telnet_printf("invalid parameter number\n");
1346: }
1347: } else if(stricmp(params[0], "IW") == 0) {
1348: if(num == 2) {
1349: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff);
1350: } else {
1351: telnet_printf("invalid parameter number\n");
1352: }
1353: } else if(stricmp(params[0], "ID") == 0) {
1354: if(num == 2) {
1355: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1])));
1356: } else {
1357: telnet_printf("invalid parameter number\n");
1358: }
1359: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) {
1360: if(num == 3) {
1361: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff);
1362: } else {
1363: telnet_printf("invalid parameter number\n");
1364: }
1365: } else if(stricmp(params[0], "OW") == 0) {
1366: if(num == 3) {
1367: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff);
1368: } else {
1369: telnet_printf("invalid parameter number\n");
1370: }
1371: } else if(stricmp(params[0], "OD") == 0) {
1372: if(num == 3) {
1373: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2]));
1374: } else {
1375: telnet_printf("invalid parameter number\n");
1376: }
1377: } else if(stricmp(params[0], "R") == 0) {
1378: if(num == 1) {
1379: debugger_regs_info(buffer);
1380: telnet_printf("%s", buffer);
1381: } else if(num == 3) {
1382: #if defined(HAS_I386)
1383: if(stricmp(params[1], "EAX") == 0) {
1384: REG32(EAX) = debugger_get_val(params[2]);
1385: } else if(stricmp(params[1], "EBX") == 0) {
1386: REG32(EBX) = debugger_get_val(params[2]);
1387: } else if(stricmp(params[1], "ECX") == 0) {
1388: REG32(ECX) = debugger_get_val(params[2]);
1389: } else if(stricmp(params[1], "EDX") == 0) {
1390: REG32(EDX) = debugger_get_val(params[2]);
1391: } else if(stricmp(params[1], "ESP") == 0) {
1392: REG32(ESP) = debugger_get_val(params[2]);
1393: } else if(stricmp(params[1], "EBP") == 0) {
1394: REG32(EBP) = debugger_get_val(params[2]);
1395: } else if(stricmp(params[1], "ESI") == 0) {
1396: REG32(ESI) = debugger_get_val(params[2]);
1397: } else if(stricmp(params[1], "EDI") == 0) {
1398: REG32(EDI) = debugger_get_val(params[2]);
1399: } else
1400: #endif
1401: if(stricmp(params[1], "AX") == 0) {
1402: REG16(AX) = debugger_get_val(params[2]);
1403: } else if(stricmp(params[1], "BX") == 0) {
1404: REG16(BX) = debugger_get_val(params[2]);
1405: } else if(stricmp(params[1], "CX") == 0) {
1406: REG16(CX) = debugger_get_val(params[2]);
1407: } else if(stricmp(params[1], "DX") == 0) {
1408: REG16(DX) = debugger_get_val(params[2]);
1409: } else if(stricmp(params[1], "SP") == 0) {
1410: REG16(SP) = debugger_get_val(params[2]);
1411: } else if(stricmp(params[1], "BP") == 0) {
1412: REG16(BP) = debugger_get_val(params[2]);
1413: } else if(stricmp(params[1], "SI") == 0) {
1414: REG16(SI) = debugger_get_val(params[2]);
1415: } else if(stricmp(params[1], "DI") == 0) {
1416: REG16(DI) = debugger_get_val(params[2]);
1417: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) {
1418: #if defined(HAS_I386)
1419: if(m_operand_size) {
1420: m_eip = debugger_get_val(params[2]);
1421: } else {
1422: m_eip = debugger_get_val(params[2]) & 0xffff;
1423: }
1424: CHANGE_PC(m_eip);
1425: #else
1426: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK;
1427: CHANGE_PC(m_pc);
1428: #endif
1429: } else if(stricmp(params[1], "AL") == 0) {
1430: REG8(AL) = debugger_get_val(params[2]);
1431: } else if(stricmp(params[1], "AH") == 0) {
1432: REG8(AH) = debugger_get_val(params[2]);
1433: } else if(stricmp(params[1], "BL") == 0) {
1434: REG8(BL) = debugger_get_val(params[2]);
1435: } else if(stricmp(params[1], "BH") == 0) {
1436: REG8(BH) = debugger_get_val(params[2]);
1437: } else if(stricmp(params[1], "CL") == 0) {
1438: REG8(CL) = debugger_get_val(params[2]);
1439: } else if(stricmp(params[1], "CH") == 0) {
1440: REG8(CH) = debugger_get_val(params[2]);
1441: } else if(stricmp(params[1], "DL") == 0) {
1442: REG8(DL) = debugger_get_val(params[2]);
1443: } else if(stricmp(params[1], "DH") == 0) {
1444: REG8(DH) = debugger_get_val(params[2]);
1445: } else {
1446: telnet_printf("unknown register %s\n", params[1]);
1447: }
1448: } else {
1449: telnet_printf("invalid parameter number\n");
1450: }
1451: } else if(_tcsicmp(params[0], "S") == 0) {
1452: if(num >= 4) {
1453: UINT32 cur_seg = debugger_get_seg(params[1], data_seg);
1454: UINT32 cur_ofs = debugger_get_ofs(params[1]);
1455: UINT32 end_seg = debugger_get_seg(params[2], cur_seg);
1456: UINT32 end_ofs = debugger_get_ofs(params[2]);
1457: UINT8 list[32];
1458:
1459: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1460: list[j] = debugger_get_val(params[i]);
1461: }
1462: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) {
1463: bool found = true;
1464: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1465: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) {
1466: found = false;
1467: break;
1468: }
1469: }
1470: if(found) {
1471: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs);
1472: }
1473: if((cur_ofs += 1) > 0xffff) {
1474: cur_seg += 0x1000;
1475: cur_ofs -= 0x10000;
1476: }
1477: }
1478: } else {
1479: telnet_printf("invalid parameter number\n");
1480: }
1481: } else if(stricmp(params[0], "U") == 0) {
1482: if(num <= 3) {
1483: if(num >= 2) {
1484: dasm_seg = debugger_get_seg(params[1], dasm_seg);
1485: dasm_ofs = debugger_get_ofs(params[1]);
1486: }
1487: if(num == 3) {
1488: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg);
1489: UINT32 end_ofs = debugger_get_ofs(params[2]);
1490:
1491: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) {
1492: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1493: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1494: for(int i = 0; i < len; i++) {
1495: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1496: }
1497: for(int i = len; i < 8; i++) {
1498: telnet_printf(" ");
1499: }
1500: telnet_printf(" %s\n", buffer);
1501: if((dasm_ofs += len) > 0xffff) {
1502: dasm_seg += 0x1000;
1503: dasm_ofs -= 0x10000;
1504: }
1505: }
1506: } else {
1507: for(int i = 0; i < 16; i++) {
1508: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1509: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1510: for(int i = 0; i < len; i++) {
1511: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1512: }
1513: for(int i = len; i < 8; i++) {
1514: telnet_printf(" ");
1515: }
1516: telnet_printf(" %s\n", buffer);
1517: if((dasm_ofs += len) > 0xffff) {
1518: dasm_seg += 0x1000;
1519: dasm_ofs -= 0x10000;
1520: }
1521: }
1522: }
1523: prev_command[1] = '\0'; // remove parameters to disassemble continuously
1524: } else {
1525: telnet_printf("invalid parameter number\n");
1526: }
1527: } else if(stricmp(params[0], "H") == 0) {
1528: if(num == 3) {
1529: UINT32 l = debugger_get_val(params[1]);
1530: UINT32 r = debugger_get_val(params[2]);
1531: telnet_printf("%08X %08X\n", l + r, l - r);
1532: } else {
1533: telnet_printf("invalid parameter number\n");
1534: }
1535: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) {
1536: break_point_t *break_point_ptr;
1537: #define GET_BREAK_POINT_PTR() { \
1538: if(params[0][0] == 'R') { \
1539: break_point_ptr = &rd_break_point; \
1540: } else if(params[0][0] == 'W') { \
1541: break_point_ptr = &wr_break_point; \
1542: } else if(params[0][0] == 'I') { \
1543: break_point_ptr = &in_break_point; \
1544: } else if(params[0][0] == 'O') { \
1545: break_point_ptr = &out_break_point; \
1546: } else { \
1547: break_point_ptr = &break_point; \
1548: } \
1549: }
1550: GET_BREAK_POINT_PTR();
1551: if(num == 2) {
1552: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1553: UINT32 ofs = debugger_get_ofs(params[1]);
1554: bool found = false;
1555: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1556: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) {
1557: break_point_ptr->table[i].addr = (seg << 4) + ofs;
1558: break_point_ptr->table[i].seg = seg;
1559: break_point_ptr->table[i].ofs = ofs;
1560: break_point_ptr->table[i].status = 1;
1561: found = true;
1562: }
1563: }
1564: if(!found) {
1565: telnet_printf("too many break points\n");
1566: }
1567: } else {
1568: telnet_printf("invalid parameter number\n");
1569: }
1570: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) {
1571: break_point_t *break_point_ptr;
1572: GET_BREAK_POINT_PTR();
1573: if(num == 2) {
1574: UINT32 addr = debugger_get_val(params[1]);
1575: bool found = false;
1576: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1577: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) {
1578: break_point_ptr->table[i].addr = addr;
1579: break_point_ptr->table[i].status = 1;
1580: found = true;
1581: }
1582: }
1583: if(!found) {
1584: telnet_printf("too many break points\n");
1585: }
1586: } else {
1587: telnet_printf("invalid parameter number\n");
1588: }
1589: } 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) {
1590: break_point_t *break_point_ptr;
1591: GET_BREAK_POINT_PTR();
1592: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1593: memset(break_point_ptr, 0, sizeof(break_point_t));
1594: } else if(num >= 2) {
1595: for(int i = 1; i < num; i++) {
1596: int index = debugger_get_val(params[i]);
1597: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1598: telnet_printf("invalid index %x\n", index);
1599: } else {
1600: break_point_ptr->table[index - 1].addr = 0;
1601: break_point_ptr->table[index - 1].seg = 0;
1602: break_point_ptr->table[index - 1].ofs = 0;
1603: break_point_ptr->table[index - 1].status = 0;
1604: }
1605: }
1606: } else {
1607: telnet_printf("invalid parameter number\n");
1608: }
1609: } 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 ||
1610: 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) {
1611: break_point_t *break_point_ptr;
1612: GET_BREAK_POINT_PTR();
1613: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1614: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1615: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1616: if(break_point_ptr->table[i].status != 0) {
1617: break_point_ptr->table[i].status = enabled ? 1 : -1;
1618: }
1619: }
1620: } else if(num >= 2) {
1621: for(int i = 1; i < num; i++) {
1622: int index = debugger_get_val(params[i]);
1623: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1624: telnet_printf("invalid index %x\n", index);
1625: } else if(break_point_ptr->table[index - 1].status == 0) {
1626: telnet_printf("break point %x is null\n", index);
1627: } else {
1628: break_point_ptr->table[index - 1].status = enabled ? 1 : -1;
1629: }
1630: }
1631: } else {
1632: telnet_printf("invalid parameter number\n");
1633: }
1634: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) {
1635: break_point_t *break_point_ptr;
1636: GET_BREAK_POINT_PTR();
1637: if(num == 1) {
1638: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1639: if(break_point_ptr->table[i].status) {
1640: 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);
1641: }
1642: }
1643: } else {
1644: telnet_printf("invalid parameter number\n");
1645: }
1646: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) {
1647: break_point_t *break_point_ptr;
1648: GET_BREAK_POINT_PTR();
1649: if(num == 1) {
1650: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1651: if(break_point_ptr->table[i].status) {
1652: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr);
1653: }
1654: }
1655: } else {
1656: telnet_printf("invalid parameter number\n");
1657: }
1658: } else if(stricmp(params[0], "INTBP") == 0) {
1659: if(num >= 2 && num <= 4) {
1660: int int_num = debugger_get_val(params[1]);
1661: UINT8 ah = 0, ah_registered = 0;
1662: UINT8 al = 0, al_registered = 0;
1663: if(num >= 3) {
1664: ah = debugger_get_val(params[2]);
1665: ah_registered = 1;
1666: }
1667: if(num == 4) {
1668: al = debugger_get_val(params[3]);
1669: al_registered = 1;
1670: }
1671: bool found = false;
1672: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1673: if(int_break_point.table[i].status == 0 || (
1674: int_break_point.table[i].int_num == int_num &&
1675: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered &&
1676: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) {
1677: int_break_point.table[i].int_num = int_num;
1678: int_break_point.table[i].ah = ah;
1679: int_break_point.table[i].ah_registered = ah_registered;
1680: int_break_point.table[i].al = al;
1681: int_break_point.table[i].al_registered = al_registered;
1682: int_break_point.table[i].status = 1;
1683: found = true;
1684: }
1685: }
1686: if(!found) {
1687: telnet_printf("too many break points\n");
1688: }
1689: } else {
1690: telnet_printf("invalid parameter number\n");
1691: }
1692: } else if(stricmp(params[0], "INTBC") == 0) {
1693: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1694: memset(&int_break_point, 0, sizeof(int_break_point_t));
1695: } else if(num >= 2) {
1696: for(int i = 1; i < num; i++) {
1697: int index = debugger_get_val(params[i]);
1698: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1699: telnet_printf("invalid index %x\n", index);
1700: } else {
1701: int_break_point.table[index - 1].int_num = 0;
1702: int_break_point.table[index - 1].ah = 0;
1703: int_break_point.table[index - 1].ah_registered = 0;
1704: int_break_point.table[index - 1].al = 0;
1705: int_break_point.table[index - 1].al_registered = 0;
1706: int_break_point.table[index - 1].status = 0;
1707: }
1708: }
1709: } else {
1710: telnet_printf("invalid parameter number\n");
1711: }
1712: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) {
1713: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1714: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1715: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1716: if(int_break_point.table[i].status != 0) {
1717: int_break_point.table[i].status = enabled ? 1 : -1;
1718: }
1719: }
1720: } else if(num >= 2) {
1721: for(int i = 1; i < num; i++) {
1722: int index = debugger_get_val(params[i]);
1723: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1724: telnet_printf("invalid index %x\n", index);
1725: } else if(int_break_point.table[index - 1].status == 0) {
1726: telnet_printf("break point %x is null\n", index);
1727: } else {
1728: int_break_point.table[index - 1].status = enabled ? 1 : -1;
1729: }
1730: }
1731: } else {
1732: telnet_printf("invalid parameter number\n");
1733: }
1734: } else if(stricmp(params[0], "INTBL") == 0) {
1735: if(num == 1) {
1736: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1737: if(int_break_point.table[i].status) {
1738: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num);
1739: if(int_break_point.table[i].ah_registered) {
1740: telnet_printf(" %02X", int_break_point.table[i].ah);
1741: }
1742: if(int_break_point.table[i].al_registered) {
1743: telnet_printf(" %02X", int_break_point.table[i].al);
1744: }
1745: telnet_printf("\n");
1746: }
1747: }
1748: } else {
1749: telnet_printf("invalid parameter number\n");
1750: }
1751: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) {
1752: if(num == 1 || num == 2) {
1753: break_point_t break_point_stored;
1754: bool break_points_stored = false;
1755:
1756: if(stricmp(params[0], "P") == 0) {
1757: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1758: memset(&break_point, 0, sizeof(break_point_t));
1759: break_points_stored = true;
1760:
1761: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip);
1762: break_point.table[0].status = 1;
1763: } else if(num >= 2) {
1764: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1765: memset(&break_point, 0, sizeof(break_point_t));
1766: break_points_stored = true;
1767:
1768: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1769: UINT32 ofs = debugger_get_ofs(params[1]);
1770: break_point.table[0].addr = (seg << 4) + ofs;
1771: break_point.table[0].seg = seg;
1772: break_point.table[0].ofs = ofs;
1773: break_point.table[0].status = 1;
1774: }
1775: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1776: now_going = true;
1777: now_suspended = false;
1778:
1779: telnet_command("\033[2l"); // key unlock
1780: while(!m_halted && !now_suspended) {
1781: if(telnet_kbhit()) {
1782: break;
1783: }
1784: Sleep(10);
1785: }
1786: now_going = false;
1787: telnet_command("\033[2h"); // key lock
1788:
1789: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1790: Sleep(100);
1791: if(!m_halted && !now_suspended) {
1792: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1793: telnet_printf("waiting until cpu is suspended...\n");
1794: }
1795: }
1796: while(!m_halted && !now_suspended) {
1797: if(telnet_disconnected()) {
1798: break;
1799: }
1800: Sleep(10);
1801: }
1802: dasm_seg = SREG(CS);
1803: dasm_ofs = m_eip;
1804:
1805: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1806: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1807: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1808:
1809: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1810: debugger_regs_info(buffer);
1811: telnet_printf("%s", buffer);
1812:
1813: if(break_point.hit) {
1814: if(stricmp(params[0], "G") == 0 && num == 1) {
1815: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1816: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1817: }
1818: } else if(rd_break_point.hit) {
1819: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1820: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1821: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1822: m_prev_cs, m_prev_eip);
1823: } else if(wr_break_point.hit) {
1824: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1825: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1826: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1827: m_prev_cs, m_prev_eip);
1828: } else if(in_break_point.hit) {
1829: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1830: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1831: in_break_point.table[in_break_point.hit - 1].addr,
1832: m_prev_cs, m_prev_eip);
1833: } else if(out_break_point.hit) {
1834: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1835: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1836: out_break_point.table[out_break_point.hit - 1].addr,
1837: m_prev_cs, m_prev_eip);
1838: } else if(int_break_point.hit) {
1839: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1840: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1841: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1842: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1843: }
1844: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1845: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1846: }
1847: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1848: } else {
1849: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1850: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1851: }
1852: if(break_points_stored) {
1853: memcpy(&break_point, &break_point_stored, sizeof(break_point_t));
1854: }
1855: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1856: debugger_dasm(buffer, SREG(CS), m_eip);
1857: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1858: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1859: } else {
1860: telnet_printf("invalid parameter number\n");
1861: }
1862: } else if(stricmp(params[0], "T") == 0) {
1863: if(num == 1 || num == 2) {
1864: int steps = 1;
1865: if(num >= 2) {
1866: steps = debugger_get_val(params[1]);
1867: }
1868:
1869: telnet_command("\033[2l"); // key unlock
1870: while(steps-- > 0) {
1871: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1872: now_going = false;
1873: now_suspended = false;
1874:
1875: while(!m_halted && !now_suspended) {
1876: if(telnet_disconnected()) {
1877: break;
1878: }
1879: Sleep(10);
1880: }
1881: dasm_seg = SREG(CS);
1882: dasm_ofs = m_eip;
1883:
1884: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1885: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1886: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1887:
1888: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1889: debugger_regs_info(buffer);
1890: telnet_printf("%s", buffer);
1891:
1892: 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()) {
1893: break;
1894: }
1895: }
1896: telnet_command("\033[2h"); // key lock
1897:
1898: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1899: Sleep(100);
1900: if(!m_halted && !now_suspended) {
1901: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1902: telnet_printf("waiting until cpu is suspended...\n");
1903: }
1904: }
1905: while(!m_halted && !now_suspended) {
1906: if(telnet_disconnected()) {
1907: break;
1908: }
1909: Sleep(10);
1910: }
1911: if(break_point.hit) {
1912: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1913: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1914: } else if(rd_break_point.hit) {
1915: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1916: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1917: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1918: m_prev_cs, m_prev_eip);
1919: } else if(wr_break_point.hit) {
1920: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1921: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1922: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1923: m_prev_cs, m_prev_eip);
1924: } else if(in_break_point.hit) {
1925: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1926: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1927: in_break_point.table[in_break_point.hit - 1].addr,
1928: m_prev_cs, m_prev_eip);
1929: } else if(out_break_point.hit) {
1930: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1931: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1932: out_break_point.table[out_break_point.hit - 1].addr,
1933: m_prev_cs, m_prev_eip);
1934: } else if(int_break_point.hit) {
1935: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1936: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1937: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1938: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1939: }
1940: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1941: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1942: }
1943: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1944: } else if(steps > 0) {
1945: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1946: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1947: }
1948: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1949: debugger_dasm(buffer, SREG(CS), m_eip);
1950: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1951: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1952: } else {
1953: telnet_printf("invalid parameter number\n");
1954: }
1955: } else if(stricmp(params[0], "Q") == 0) {
1956: break;
1957: } else if(stricmp(params[0], "X") == 0) {
1958: debugger_process_info(buffer);
1959: telnet_printf("%s", buffer);
1960: } else if(stricmp(params[0], ">") == 0) {
1961: if(num == 2) {
1962: if(fp_debugger != NULL) {
1963: fclose(fp_debugger);
1964: fp_debugger = NULL;
1965: }
1966: fp_debugger = fopen(params[1], "w");
1967: } else {
1968: telnet_printf("invalid parameter number\n");
1969: }
1970: } else if(stricmp(params[0], "<") == 0) {
1971: if(num == 2) {
1972: if(fi_debugger != NULL) {
1973: fclose(fi_debugger);
1974: fi_debugger = NULL;
1975: }
1976: fi_debugger = fopen(params[1], "r");
1977: } else {
1978: telnet_printf("invalid parameter number\n");
1979: }
1980: } else if(stricmp(params[0], "?") == 0) {
1981: telnet_printf("D [<start> [<end>]] - dump memory\n");
1982: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n");
1983: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n");
1984: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n");
1985: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n");
1986:
1987: telnet_printf("R - show registers\n");
1988: telnet_printf("R <reg> <value> - edit register\n");
1989: telnet_printf("S <start> <end> <list> - search\n");
1990: telnet_printf("U [<start> [<end>]] - unassemble\n");
1991:
1992: telnet_printf("H <value> <value> - hexadd\n");
1993:
1994: telnet_printf("BP <address> - set breakpoint\n");
1995: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n");
1996: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n");
1997: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n");
1998: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n");
1999: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n");
2000:
2001: telnet_printf("G - go (press enter key to break)\n");
2002: telnet_printf("G <address> - go and break at address\n");
2003: telnet_printf("P - trace one opcode (step over)\n");
2004: telnet_printf("T [<count>] - trace (step in)\n");
2005: telnet_printf("Q - quit\n");
2006: telnet_printf("X - show dos process info\n");
2007:
2008: telnet_printf("> <filename> - output logfile\n");
2009: telnet_printf("< <filename> - input commands from file\n");
2010:
2011: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n");
2012: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n");
2013: } else {
2014: telnet_printf("unknown command %s\n", params[0]);
2015: }
2016: }
2017: }
2018: if(fp_debugger != NULL) {
2019: fclose(fp_debugger);
2020: fp_debugger = NULL;
2021: }
2022: if(fi_debugger != NULL) {
2023: fclose(fi_debugger);
2024: fi_debugger = NULL;
2025: }
2026: now_debugging = now_going = now_suspended = force_suspend = false;
2027: closesocket(cli_socket);
2028: }
2029:
2030: const char *debugger_get_ttermpro_path()
2031: {
2032: static char path[MAX_PATH] = {0};
2033:
2034: if(getenv("ProgramFiles")) {
2035: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles"));
2036: }
2037: return(path);
2038: }
2039:
2040: const char *debugger_get_ttermpro_x86_path()
2041: {
2042: static char path[MAX_PATH] = {0};
2043:
2044: if(getenv("ProgramFiles(x86)")) {
2045: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)"));
2046: }
2047: return(path);
2048: }
2049:
2050: const char *debugger_get_putty_path()
2051: {
2052: static char path[MAX_PATH] = {0};
2053:
2054: if(getenv("ProgramFiles")) {
2055: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles"));
2056: }
2057: return(path);
2058: }
2059:
2060: const char *debugger_get_putty_x86_path()
2061: {
2062: static char path[MAX_PATH] = {0};
2063:
2064: if(getenv("ProgramFiles(x86)")) {
2065: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)"));
2066: }
2067: return(path);
2068: }
2069:
2070: const char *debugger_get_telnet_path()
2071: {
2072: // NOTE: When you run 32bit version of msdos.exe on Windows x64,
2073: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64.
2074: // But 32bit version of telnet.exe will not be installed in SysWOW64
2075: // and 64bit version of telnet.exe will be installed in System32.
2076: static char path[MAX_PATH] = {0};
2077:
2078: if(getenv("windir") != NULL) {
2079: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir"));
2080: }
2081: return(path);
2082: }
2083:
2084: DWORD WINAPI debugger_thread(LPVOID)
2085: {
2086: WSADATA was_data;
2087: struct sockaddr_in svr_addr;
2088: struct sockaddr_in cli_addr;
2089: int cli_addr_len = sizeof(cli_addr);
2090: int port = 23;
2091: int bind_stat = SOCKET_ERROR;
2092: struct timeval timeout;
2093:
2094: WSAStartup(MAKEWORD(2,0), &was_data);
2095:
2096: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
2097: memset(&svr_addr, 0, sizeof(svr_addr));
2098: svr_addr.sin_family = AF_INET;
2099: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
2100:
2101: while(!m_halted && port < 10000) {
2102: svr_addr.sin_port = htons(port);
2103: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
2104: break;
2105: } else {
2106: port = (port == 23) ? 9000 : (port + 1);
2107: }
2108: }
2109: if(bind_stat == 0) {
2110: timeout.tv_sec = 1;
2111: timeout.tv_usec = 0;
1.1.1.45 root 2112: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
1.1.1.33 root 2113:
2114: listen(svr_socket, 1);
2115:
2116: char command[MAX_PATH] = {0};
2117: STARTUPINFO si;
2118: PROCESS_INFORMATION pi;
2119:
2120: if(_access(debugger_get_ttermpro_path(), 0) == 0) {
2121: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port);
2122: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) {
2123: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port);
2124: } else if(_access(debugger_get_putty_path(), 0) == 0) {
2125: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port);
2126: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) {
2127: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port);
2128: } else if(_access(debugger_get_telnet_path(), 0) == 0) {
2129: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port);
2130: }
2131: if(command[0] != '\0') {
2132: memset(&si, 0, sizeof(STARTUPINFO));
2133: memset(&pi, 0, sizeof(PROCESS_INFORMATION));
2134: CreateProcess(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
2135: }
2136:
2137: while(!m_halted) {
2138: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
2139: u_long val = 1;
2140: ioctlsocket(cli_socket, FIONBIO, &val);
2141: debugger_main();
2142: }
2143: }
2144: }
2145: }
2146: WSACleanup();
2147: return(0);
2148: }
2149: #endif
2150:
2151: /* ----------------------------------------------------------------------------
1.1 root 2152: main
2153: ---------------------------------------------------------------------------- */
2154:
1.1.1.28 root 2155: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
2156: {
2157: if(dwCtrlType == CTRL_BREAK_EVENT) {
1.1.1.33 root 2158: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 2159: #ifdef USE_SERVICE_THREAD
2160: EnterCriticalSection(&key_buf_crit_sect);
2161: #endif
1.1.1.33 root 2162: key_buf_char->clear();
2163: key_buf_scan->clear();
1.1.1.35 root 2164: #ifdef USE_SERVICE_THREAD
2165: LeaveCriticalSection(&key_buf_crit_sect);
2166: #endif
1.1.1.33 root 2167: }
2168: // key_code = key_recv = 0;
1.1.1.28 root 2169: return TRUE;
2170: } else if(dwCtrlType == CTRL_C_EVENT) {
2171: return TRUE;
2172: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
2173: // this program will be terminated abnormally, do minimum end process
2174: exit_handler();
2175: exit(1);
2176: }
2177: return FALSE;
2178: }
2179:
2180: void exit_handler()
2181: {
2182: if(temp_file_created) {
2183: DeleteFile(temp_file_path);
2184: temp_file_created = false;
2185: }
2186: if(key_buf_char != NULL) {
2187: key_buf_char->release();
2188: delete key_buf_char;
2189: key_buf_char = NULL;
2190: }
2191: if(key_buf_scan != NULL) {
2192: key_buf_scan->release();
2193: delete key_buf_scan;
2194: key_buf_scan = NULL;
2195: }
1.1.1.32 root 2196: #ifdef SUPPORT_XMS
2197: msdos_xms_release();
2198: #endif
1.1.1.28 root 2199: hardware_release();
2200: }
2201:
1.1.1.35 root 2202: #ifdef USE_VRAM_THREAD
1.1.1.28 root 2203: DWORD WINAPI vram_thread(LPVOID)
2204: {
2205: while(!m_halted) {
2206: EnterCriticalSection(&vram_crit_sect);
2207: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
2208: vram_flush_char();
2209: }
2210: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
2211: vram_flush_attr();
2212: }
2213: vram_last_length_char = vram_length_char;
2214: vram_last_length_attr = vram_length_attr;
2215: LeaveCriticalSection(&vram_crit_sect);
2216: // this is about half the maximum keyboard repeat rate - any
2217: // lower tends to be jerky, any higher misses updates
2218: Sleep(15);
2219: }
2220: return 0;
2221: }
2222: #endif
2223:
1.1.1.45 root 2224: long get_section_in_exec_file(FILE *fp, const char *name)
1.1.1.28 root 2225: {
2226: UINT8 header[0x400];
2227:
2228: long position = ftell(fp);
2229: fseek(fp, 0, SEEK_SET);
2230: fread(header, sizeof(header), 1, fp);
2231: fseek(fp, position, SEEK_SET);
2232:
2233: try {
2234: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2235: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2236: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2237: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2238: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2239: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2240:
2241: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
2242: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
2243: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
2244: return(sectionHeader->PointerToRawData);
2245: }
2246: }
2247: } catch(...) {
2248: }
2249: return(0);
2250: }
2251:
1.1.1.10 root 2252: bool is_started_from_command_prompt()
2253: {
1.1.1.18 root 2254: bool ret = false;
2255:
2256: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
2257: if(hLibrary) {
2258: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
2259: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
2260: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
2261: if(lpfnGetConsoleProcessList) {
2262: DWORD pl;
2263: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
2264: FreeLibrary(hLibrary);
2265: return(ret);
2266: }
2267: FreeLibrary(hLibrary);
2268: }
2269:
2270: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2271: if(hSnapshot != INVALID_HANDLE_VALUE) {
2272: DWORD dwParentProcessID = 0;
2273: PROCESSENTRY32 pe32;
2274: pe32.dwSize = sizeof(PROCESSENTRY32);
2275: if(Process32First(hSnapshot, &pe32)) {
2276: do {
2277: if(pe32.th32ProcessID == GetCurrentProcessId()) {
2278: dwParentProcessID = pe32.th32ParentProcessID;
2279: break;
2280: }
2281: } while(Process32Next(hSnapshot, &pe32));
2282: }
2283: CloseHandle(hSnapshot);
2284: if(dwParentProcessID != 0) {
2285: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
2286: if(hProcess != NULL) {
2287: HMODULE hMod;
2288: DWORD cbNeeded;
2289: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
2290: char module_name[MAX_PATH];
2291: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
2292: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
2293: }
2294: }
2295: CloseHandle(hProcess);
2296: }
2297: }
2298: }
2299: return(ret);
1.1.1.14 root 2300: }
2301:
2302: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
2303: {
1.1.1.24 root 2304: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 2305: OSVERSIONINFOEX osvi;
2306: DWORDLONG dwlConditionMask = 0;
2307: int op = VER_GREATER_EQUAL;
2308:
2309: // Initialize the OSVERSIONINFOEX structure.
2310: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
2311: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
2312: osvi.dwMajorVersion = dwMajorVersion;
2313: osvi.dwMinorVersion = dwMinorVersion;
2314: osvi.wServicePackMajor = wServicePackMajor;
2315: osvi.wServicePackMinor = wServicePackMinor;
2316:
2317: // Initialize the condition mask.
2318: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
2319: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
2320: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
2321: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
2322:
2323: // Perform the test.
2324: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
2325: }
2326:
1.1.1.27 root 2327: void get_sio_port_numbers()
2328: {
2329: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
2330: HDEVINFO hDevInfo = 0;
2331: HKEY hKey = 0;
2332: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
2333: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
2334: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
2335: char chData[256];
2336: DWORD dwType = 0;
2337: DWORD dwSize = sizeof(chData);
2338: int port_number = 0;
2339:
2340: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
2341: if(_strnicmp(chData, "COM", 3) == 0) {
2342: port_number = atoi(chData + 3);
2343: }
2344: }
2345: RegCloseKey(hKey);
2346:
1.1.1.29 root 2347: 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 2348: continue;
2349: }
2350: if(sio_port_number[0] == 0) {
2351: sio_port_number[0] = port_number;
2352: } else if(sio_port_number[1] == 0) {
2353: sio_port_number[1] = port_number;
1.1.1.29 root 2354: } else if(sio_port_number[2] == 0) {
2355: sio_port_number[2] = port_number;
2356: } else if(sio_port_number[3] == 0) {
2357: sio_port_number[3] = port_number;
1.1.1.27 root 2358: }
1.1.1.29 root 2359: 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 2360: break;
2361: }
2362: }
2363: }
2364: }
2365: }
2366:
1.1.1.28 root 2367: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
2368:
1.1 root 2369: int main(int argc, char *argv[], char *envp[])
2370: {
1.1.1.9 root 2371: int arg_offset = 0;
2372: int standard_env = 0;
1.1.1.14 root 2373: int buf_width = 0, buf_height = 0;
1.1.1.28 root 2374: bool get_console_info_success = false;
2375: bool screen_size_changed = false;
2376:
2377: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
2378: GetModuleFileName(NULL, path, MAX_PATH);
2379: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 2380:
1.1.1.27 root 2381: char dummy_argv_0[] = "msdos.exe";
2382: char dummy_argv_1[MAX_PATH];
2383: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
2384: char new_exec_file[MAX_PATH];
2385: bool convert_cmd_file = false;
1.1.1.28 root 2386: unsigned int code_page = 0;
1.1.1.27 root 2387:
2388: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 2389: // check if command file is embedded to this execution file
2390: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 2391: FILE* fp = fopen(full, "rb");
1.1.1.28 root 2392: long offset = get_section_in_exec_file(fp, ".msdos");
2393: if(offset != 0) {
1.1.1.30 root 2394: UINT8 buffer[16];
1.1.1.28 root 2395: fseek(fp, offset, SEEK_SET);
2396: fread(buffer, sizeof(buffer), 1, fp);
2397:
2398: // restore flags
2399: stay_busy = ((buffer[0] & 0x01) != 0);
2400: no_windows = ((buffer[0] & 0x02) != 0);
2401: standard_env = ((buffer[0] & 0x04) != 0);
2402: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
2403: limit_max_memory = ((buffer[0] & 0x10) != 0);
2404: if((buffer[0] & 0x20) != 0) {
2405: get_sio_port_numbers();
2406: }
2407: if((buffer[0] & 0x40) != 0) {
2408: UMB_TOP = EMS_TOP + EMS_SIZE;
2409: support_ems = true;
1.1.1.30 root 2410: }
1.1.1.27 root 2411: #ifdef SUPPORT_XMS
1.1.1.30 root 2412: if((buffer[0] & 0x80) != 0) {
1.1.1.28 root 2413: support_xms = true;
2414: }
1.1.1.30 root 2415: #endif
1.1.1.28 root 2416: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
2417: buf_width = buffer[1] | (buffer[2] << 8);
2418: buf_height = buffer[3] | (buffer[4] << 8);
2419: }
2420: if(buffer[5] != 0) {
1.1.1.30 root 2421: dos_major_version = buffer[5];
2422: dos_minor_version = buffer[6];
2423: }
2424: if(buffer[7] != 0) {
2425: win_major_version = buffer[7];
2426: win_minor_version = buffer[8];
1.1.1.28 root 2427: }
1.1.1.30 root 2428: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
1.1.1.28 root 2429: SetConsoleCP(code_page);
2430: SetConsoleOutputCP(code_page);
2431: }
1.1.1.30 root 2432: int name_len = buffer[11];
2433: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
1.1.1.28 root 2434:
2435: // restore command file name
2436: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
2437: fread(dummy_argv_1, name_len, 1, fp);
2438:
2439: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
2440: // if original command file exists, create a temporary file name
2441: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
2442: // create a temporary command file in the current director
2443: DeleteFile(dummy_argv_1);
1.1.1.27 root 2444: } else {
1.1.1.28 root 2445: // create a temporary command file in the temporary folder
2446: GetTempPath(MAX_PATH, path);
2447: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
2448: DeleteFile(dummy_argv_1);
2449: } else {
2450: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
2451: }
1.1.1.27 root 2452: }
1.1.1.28 root 2453: // check the command file type
2454: fread(buffer, 2, 1, fp);
2455: fseek(fp, -2, SEEK_CUR);
2456: if(memcmp(buffer, "MZ", 2) != 0) {
2457: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
2458: } else {
2459: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 2460: }
2461: }
1.1.1.28 root 2462:
2463: // restore command file
2464: FILE* fo = fopen(dummy_argv_1, "wb");
2465: for(int i = 0; i < file_len; i++) {
2466: fputc(fgetc(fp), fo);
2467: }
2468: fclose(fo);
2469:
2470: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
2471: temp_file_created = true;
2472: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
2473:
2474: // adjust argc/argv
2475: for(int i = 1; i < argc && (i + 1) < 256; i++) {
2476: dummy_argv[i + 1] = argv[i];
2477: }
2478: argc++;
2479: argv = dummy_argv;
1.1.1.27 root 2480: }
2481: fclose(fp);
2482: }
1.1.1.9 root 2483: for(int i = 1; i < argc; i++) {
1.1.1.25 root 2484: if(_strnicmp(argv[i], "-b", 2) == 0) {
2485: stay_busy = true;
2486: arg_offset++;
1.1.1.27 root 2487: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
2488: if(argv[i][2] != '\0') {
2489: strcpy(new_exec_file, &argv[i][2]);
2490: } else {
2491: strcpy(new_exec_file, "new_exec_file.exe");
2492: }
2493: convert_cmd_file = true;
2494: arg_offset++;
1.1.1.28 root 2495: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
2496: if(IS_NUMERIC(argv[i][2])) {
2497: code_page = atoi(&argv[i][2]);
2498: } else {
2499: code_page = GetConsoleCP();
2500: }
2501: arg_offset++;
1.1.1.25 root 2502: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
2503: no_windows = true;
2504: arg_offset++;
2505: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 2506: standard_env = 1;
2507: arg_offset++;
1.1.1.14 root 2508: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
2509: ignore_illegal_insn = true;
2510: arg_offset++;
2511: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
2512: limit_max_memory = true;
2513: arg_offset++;
2514: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 2515: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
2516: buf_width = buf_height = 0;
2517: }
2518: if(buf_width <= 0 || buf_width > 0x7fff) {
2519: buf_width = 80;
2520: }
2521: if(buf_height <= 0 || buf_height > 0x7fff) {
2522: buf_height = 25;
2523: }
1.1.1.14 root 2524: arg_offset++;
1.1.1.25 root 2525: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 2526: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29 root 2527: char *p0 = &argv[i][2], *p1, *p2, *p3;
2528: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
2529: sio_port_number[1] = atoi(p1 + 1);
2530: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
2531: sio_port_number[2] = atoi(p2 + 1);
2532: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
2533: sio_port_number[3] = atoi(p3 + 1);
2534: }
2535: }
1.1.1.25 root 2536: }
1.1.1.29 root 2537: sio_port_number[0] = atoi(p0);
1.1.1.25 root 2538: }
1.1.1.29 root 2539: 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 2540: get_sio_port_numbers();
1.1.1.25 root 2541: }
2542: arg_offset++;
1.1.1.9 root 2543: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 2544: 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 2545: dos_major_version = argv[i][2] - '0';
2546: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2547: }
2548: arg_offset++;
2549: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
2550: 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]))) {
2551: win_major_version = argv[i][2] - '0';
2552: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 2553: }
2554: arg_offset++;
1.1.1.25 root 2555: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
2556: UMB_TOP = EMS_TOP + EMS_SIZE;
2557: support_ems = true;
2558: #ifdef SUPPORT_XMS
2559: support_xms = true;
2560: #endif
2561: arg_offset++;
1.1.1.9 root 2562: } else {
2563: break;
2564: }
2565: }
2566: if(argc < 2 + arg_offset) {
1.1 root 2567: #ifdef _WIN64
1.1.1.14 root 2568: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 2569: #else
1.1.1.14 root 2570: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 2571: #endif
1.1.1.25 root 2572: fprintf(stderr,
1.1.1.28 root 2573: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.30 root 2574: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
1.1.1.25 root 2575: "\n"
2576: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 2577: #ifdef _WIN64
1.1.1.27 root 2578: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 2579: #else
1.1.1.27 root 2580: "\t-c\tconvert command file to 32bit execution file\n"
2581: #endif
1.1.1.28 root 2582: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 2583: "\t-d\tpretend running under straight DOS, not Windows\n"
2584: "\t-e\tuse a reduced environment block\n"
2585: "\t-i\tignore invalid instructions\n"
2586: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
2587: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
2588: "\t-s\tenable serial I/O and set host's COM port numbers\n"
2589: "\t-v\tset the DOS version\n"
1.1.1.30 root 2590: "\t-w\tset the Windows version\n"
1.1.1.19 root 2591: #ifdef SUPPORT_XMS
1.1.1.28 root 2592: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 2593: #else
1.1.1.28 root 2594: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 2595: #endif
2596: );
1.1.1.10 root 2597:
2598: if(!is_started_from_command_prompt()) {
2599: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
2600: while(!_kbhit()) {
2601: Sleep(10);
2602: }
2603: }
1.1.1.20 root 2604: #ifdef _DEBUG
2605: _CrtDumpMemoryLeaks();
2606: #endif
1.1 root 2607: return(EXIT_FAILURE);
2608: }
1.1.1.27 root 2609: if(convert_cmd_file) {
2610: retval = EXIT_FAILURE;
1.1.1.28 root 2611: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 2612: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 2613: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 2614:
1.1.1.28 root 2615: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
2616: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
2617: } else if((fp = fopen(full, "rb")) == NULL) {
2618: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 2619: } else {
1.1.1.28 root 2620: long offset = get_section_in_exec_file(fp, ".msdos");
2621: if(offset != 0) {
2622: UINT8 buffer[14];
2623: fseek(fp, offset, SEEK_SET);
2624: fread(buffer, sizeof(buffer), 1, fp);
2625: memset(path, 0, sizeof(path));
2626: fread(path, buffer[9], 1, fp);
2627: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
2628: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
2629: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
2630: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
2631: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
2632: } else {
2633: // read pe header of msdos.exe
2634: UINT8 header[0x400];
2635: fseek(fp, 0, SEEK_SET);
2636: fread(header, sizeof(header), 1, fp);
2637:
2638: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2639: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2640: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2641: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2642: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2643: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
2644: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2645:
2646: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
2647: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
2648: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
2649: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
2650: if(dwExtraLastSectionBytes != 0) {
2651: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
2652: dwLastSectionSize += dwRemain;
2653: }
2654: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
2655:
2656: // store msdos.exe
2657: fseek(fp, 0, SEEK_SET);
2658: for(int i = 0; i < dwEndOfFile; i++) {
2659: if((data = fgetc(fp)) != EOF) {
2660: fputc(data, fo);
2661: } else {
2662: // we should not reach here :-(
2663: fputc(0, fo);
2664: }
2665: }
2666:
2667: // store options
2668: UINT8 flags = 0;
2669: if(stay_busy) {
2670: flags |= 0x01;
2671: }
2672: if(no_windows) {
2673: flags |= 0x02;
2674: }
2675: if(standard_env) {
2676: flags |= 0x04;
2677: }
2678: if(ignore_illegal_insn) {
2679: flags |= 0x08;
2680: }
2681: if(limit_max_memory) {
2682: flags |= 0x10;
2683: }
1.1.1.29 root 2684: 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 2685: flags |= 0x20;
2686: }
2687: if(support_ems) {
2688: flags |= 0x40;
2689: }
1.1.1.30 root 2690: #ifdef SUPPORT_XMS
2691: if(support_xms) {
2692: flags |= 0x80;
2693: }
2694: #endif
1.1.1.28 root 2695:
2696: fputc(flags, fo);
2697: fputc((buf_width >> 0) & 0xff, fo);
2698: fputc((buf_width >> 8) & 0xff, fo);
2699: fputc((buf_height >> 0) & 0xff, fo);
2700: fputc((buf_height >> 8) & 0xff, fo);
1.1.1.30 root 2701: fputc(dos_major_version, fo);
2702: fputc(dos_minor_version, fo);
2703: fputc(win_major_version, fo);
2704: fputc(win_minor_version, fo);
1.1.1.28 root 2705: fputc((code_page >> 0) & 0xff, fo);
2706: fputc((code_page >> 8) & 0xff, fo);
2707:
2708: // store command file info
2709: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
2710: int name_len = strlen(name);
2711: fseek(fs, 0, SEEK_END);
2712: long file_size = ftell(fs);
2713:
2714: fputc(name_len, fo);
2715: fputc((file_size >> 0) & 0xff, fo);
2716: fputc((file_size >> 8) & 0xff, fo);
2717: fputc((file_size >> 16) & 0xff, fo);
2718: fputc((file_size >> 24) & 0xff, fo);
2719: fwrite(name, name_len, 1, fo);
2720:
2721: // store command file
2722: fseek(fs, 0, SEEK_SET);
2723: for(int i = 0; i < file_size; i++) {
2724: if((data = fgetc(fs)) != EOF) {
2725: fputc(data, fo);
2726: } else {
2727: // we should not reach here :-(
2728: fputc(0, fo);
2729: }
2730: }
2731:
2732: // store padding data and update pe header
1.1.1.29 root 2733: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
2734: coffHeader->NumberOfSections++;
2735: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
2736: memcpy(newSectionHeader->Name, ".msdos", 6);
2737: newSectionHeader->VirtualAddress = dwVirtualAddress;
2738: newSectionHeader->PointerToRawData = dwEndOfFile;
2739: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 2740: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
2741: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
2742: if(dwExtraRawBytes != 0) {
1.1.1.29 root 2743: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 2744: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
2745: for(int i = 0; i < dwRemain; i++) {
1.1.1.29 root 2746: if(i < 2) {
2747: fputc(padding[i & 15], fo);
2748: } else {
2749: fputc(padding[(i - 2) & 15], fo);
2750: }
1.1.1.28 root 2751: }
2752: newSectionHeader->SizeOfRawData += dwRemain;
2753: }
2754: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
2755:
2756: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
2757: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
2758: if(dwExtraNewSectionBytes != 0) {
2759: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
2760: dwNewSectionSize += dwRemain;
2761: }
2762: optionalHeader->SizeOfImage += dwNewSectionSize;
2763:
2764: fseek(fo, 0, SEEK_SET);
2765: fwrite(header, sizeof(header), 1, fo);
2766:
2767: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
2768: retval = EXIT_SUCCESS;
1.1.1.27 root 2769: }
2770: }
2771: if(fp != NULL) {
2772: fclose(fp);
2773: }
2774: if(fs != NULL) {
2775: fclose(fs);
2776: }
2777: if(fo != NULL) {
2778: fclose(fo);
2779: }
2780: }
2781: #ifdef _DEBUG
2782: _CrtDumpMemoryLeaks();
2783: #endif
2784: return(retval);
2785: }
1.1 root 2786:
1.1.1.14 root 2787: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
2788:
1.1.1.23 root 2789: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2790: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 2791: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 2792:
1.1.1.28 root 2793: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 2794: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 2795: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 2796:
1.1.1.14 root 2797: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
2798: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
2799: SCR_BUF(y,x).Char.AsciiChar = ' ';
2800: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 2801: }
2802: }
1.1.1.28 root 2803: if(get_console_info_success) {
1.1.1.12 root 2804: scr_width = csbi.dwSize.X;
1.1.1.14 root 2805: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2806:
1.1.1.28 root 2807: // v-text shadow buffer size must be lesser than 0x7fd0
2808: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 2809: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
2810: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
2811: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 2812: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 2813: scr_width = 80;
2814: scr_height = 25;
2815: }
1.1.1.28 root 2816: screen_size_changed = true;
1.1.1.14 root 2817: }
1.1.1.12 root 2818: } else {
2819: // for a proof (not a console)
2820: scr_width = 80;
2821: scr_height = 25;
2822: }
1.1.1.14 root 2823: scr_buf_size.X = scr_width;
2824: scr_buf_size.Y = scr_height;
2825: scr_buf_pos.X = scr_buf_pos.Y = 0;
2826: scr_top = csbi.srWindow.Top;
1.1 root 2827: cursor_moved = false;
2828:
1.1.1.35 root 2829: #ifdef USE_SERVICE_THREAD
2830: InitializeCriticalSection(&input_crit_sect);
2831: InitializeCriticalSection(&key_buf_crit_sect);
2832: InitializeCriticalSection(&putch_crit_sect);
2833: #endif
1.1.1.25 root 2834: key_buf_char = new FIFO(256);
2835: key_buf_scan = new FIFO(256);
1.1 root 2836:
2837: hardware_init();
2838:
1.1.1.33 root 2839: #ifdef USE_DEBUGGER
2840: debugger_init();
2841: #endif
2842:
1.1.1.9 root 2843: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 2844: retval = EXIT_FAILURE;
2845: } else {
1.1.1.27 root 2846: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 2847: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
2848: #endif
2849: SetConsoleCtrlHandler(ctrl_handler, TRUE);
2850:
1.1.1.28 root 2851: if(screen_size_changed) {
1.1.1.24 root 2852: change_console_size(scr_width, scr_height);
2853: }
1.1.1.8 root 2854: TIMECAPS caps;
2855: timeGetDevCaps(&caps, sizeof(TIMECAPS));
2856: timeBeginPeriod(caps.wPeriodMin);
1.1.1.35 root 2857: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2858: InitializeCriticalSection(&vram_crit_sect);
2859: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
2860: #endif
1.1.1.33 root 2861: #ifdef USE_DEBUGGER
2862: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL));
2863: // wait until telnet client starts and connects to me
2864: if(_access(debugger_get_ttermpro_path(), 0) == 0 ||
2865: _access(debugger_get_ttermpro_x86_path(), 0) == 0 ||
2866: _access(debugger_get_putty_path(), 0) == 0 ||
2867: _access(debugger_get_putty_x86_path(), 0) == 0 ||
2868: _access(debugger_get_telnet_path(), 0) == 0) {
2869: for(int i = 0; i < 100 && cli_socket == 0; i++) {
2870: Sleep(100);
2871: }
2872: }
2873: #endif
1.1 root 2874: hardware_run();
1.1.1.35 root 2875: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2876: vram_flush();
2877: DeleteCriticalSection(&vram_crit_sect);
2878: #endif
1.1.1.24 root 2879: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 2880:
1.1.1.24 root 2881: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 2882: if(get_console_info_success) {
1.1.1.23 root 2883: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2884: if(restore_console_on_exit) {
1.1.1.14 root 2885: // window can't be bigger than buffer,
2886: // buffer can't be smaller than window,
2887: // so make a tiny window,
2888: // set the required buffer,
2889: // then set the required window
2890: SMALL_RECT rect;
2891: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
2892: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 2893: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 2894: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 2895: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2896: }
1.1.1.14 root 2897: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
2898: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 2899: }
1.1.1.24 root 2900: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
2901:
1.1 root 2902: msdos_finish();
1.1.1.14 root 2903:
2904: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 2905: }
1.1.1.35 root 2906: if(temp_file_created) {
2907: DeleteFile(temp_file_path);
2908: temp_file_created = false;
2909: }
1.1.1.10 root 2910: hardware_finish();
2911:
1.1.1.28 root 2912: if(key_buf_char != NULL) {
2913: key_buf_char->release();
2914: delete key_buf_char;
2915: key_buf_char = NULL;
2916: }
2917: if(key_buf_scan != NULL) {
2918: key_buf_scan->release();
2919: delete key_buf_scan;
2920: key_buf_scan = NULL;
2921: }
1.1.1.35 root 2922: #ifdef USE_SERVICE_THREAD
2923: DeleteCriticalSection(&input_crit_sect);
2924: DeleteCriticalSection(&key_buf_crit_sect);
2925: DeleteCriticalSection(&putch_crit_sect);
2926: #endif
1.1.1.20 root 2927: #ifdef _DEBUG
2928: _CrtDumpMemoryLeaks();
2929: #endif
1.1 root 2930: return(retval);
2931: }
2932:
1.1.1.20 root 2933: /* ----------------------------------------------------------------------------
2934: console
2935: ---------------------------------------------------------------------------- */
2936:
1.1.1.14 root 2937: void change_console_size(int width, int height)
1.1.1.12 root 2938: {
1.1.1.23 root 2939: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2940: CONSOLE_SCREEN_BUFFER_INFO csbi;
2941: SMALL_RECT rect;
2942: COORD co;
2943:
2944: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 2945: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
2946: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
2947: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
2948: SET_RECT(rect, 0, 0, width - 1, height - 1);
2949: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2950: } else if(csbi.dwCursorPosition.Y > height - 1) {
2951: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
2952: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2953: SET_RECT(rect, 0, 0, width - 1, height - 1);
2954: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 2955: }
2956: }
1.1.1.14 root 2957: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 2958: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 2959: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 2960: SetConsoleCursorPosition(hStdout, co);
2961: cursor_moved = true;
2962: }
1.1.1.14 root 2963:
2964: // window can't be bigger than buffer,
2965: // buffer can't be smaller than window,
2966: // so make a tiny window,
2967: // set the required buffer,
2968: // then set the required window
2969: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 2970: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 2971: co.X = width;
2972: co.Y = height;
1.1.1.12 root 2973: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 2974: SET_RECT(rect, 0, 0, width - 1, height - 1);
2975: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2976:
2977: scr_width = scr_buf_size.X = width;
2978: scr_height = scr_buf_size.Y = height;
2979: scr_top = 0;
2980:
2981: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2982:
2983: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 2984: text_vram_end_address = text_vram_top_address + regen;
2985: shadow_buffer_end_address = shadow_buffer_top_address + regen;
2986:
1.1.1.14 root 2987: if(regen > 0x4000) {
2988: regen = 0x8000;
2989: vram_pages = 1;
2990: } else if(regen > 0x2000) {
2991: regen = 0x4000;
2992: vram_pages = 2;
2993: } else if(regen > 0x1000) {
2994: regen = 0x2000;
2995: vram_pages = 4;
2996: } else {
2997: regen = 0x1000;
2998: vram_pages = 8;
2999: }
1.1.1.15 root 3000: *(UINT16 *)(mem + 0x44a) = scr_width;
3001: *(UINT16 *)(mem + 0x44c) = regen;
3002: *(UINT8 *)(mem + 0x484) = scr_height - 1;
3003:
1.1.1.24 root 3004: mouse.min_position.x = 0;
3005: mouse.min_position.y = 0;
1.1.1.34 root 3006: mouse.max_position.x = 8 * (scr_width - 1);
3007: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 3008:
1.1.1.15 root 3009: restore_console_on_exit = true;
1.1.1.14 root 3010: }
3011:
3012: void clear_scr_buffer(WORD attr)
3013: {
3014: for(int y = 0; y < scr_height; y++) {
3015: for(int x = 0; x < scr_width; x++) {
3016: SCR_BUF(y,x).Char.AsciiChar = ' ';
3017: SCR_BUF(y,x).Attributes = attr;
3018: }
3019: }
1.1.1.12 root 3020: }
3021:
1.1.1.24 root 3022: bool update_console_input()
1.1 root 3023: {
1.1.1.35 root 3024: #ifdef USE_SERVICE_THREAD
3025: EnterCriticalSection(&input_crit_sect);
3026: #endif
1.1.1.23 root 3027: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 3028: DWORD dwNumberOfEvents = 0;
1.1 root 3029: DWORD dwRead;
3030: INPUT_RECORD ir[16];
1.1.1.24 root 3031: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
3032: bool result = false;
1.1 root 3033:
1.1.1.8 root 3034: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
3035: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
3036: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 3037: if(ir[i].EventType & MOUSE_EVENT) {
1.1.1.34 root 3038: if(mouse.hidden == 0) {
3039: // NOTE: if restore_console_on_exit, console is not scrolled
3040: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
3041: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
3042: }
3043: // FIXME: character size is always 8x8 ???
3044: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
3045: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
3046:
3047: if(mouse.position.x != x || mouse.position.y != y) {
3048: mouse.position.x = x;
3049: mouse.position.y = y;
3050: mouse.status |= 1;
1.1.1.43 root 3051: mouse.status_alt |= 1;
1.1.1.34 root 3052: }
3053: }
3054: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
3055: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
3056: static const DWORD bits[] = {
3057: FROM_LEFT_1ST_BUTTON_PRESSED, // left
3058: RIGHTMOST_BUTTON_PRESSED, // right
3059: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
3060: };
3061: bool prev_status = mouse.buttons[i].status;
3062: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
3063:
3064: if(!prev_status && mouse.buttons[i].status) {
3065: mouse.buttons[i].pressed_times++;
3066: mouse.buttons[i].pressed_position.x = mouse.position.x;
3067: mouse.buttons[i].pressed_position.y = mouse.position.x;
1.1.1.43 root 3068: if(i < 2) {
3069: mouse.status_alt |= 2 << (i * 2);
3070: }
1.1.1.34 root 3071: mouse.status |= 2 << (i * 2);
3072: } else if(prev_status && !mouse.buttons[i].status) {
3073: mouse.buttons[i].released_times++;
3074: mouse.buttons[i].released_position.x = mouse.position.x;
3075: mouse.buttons[i].released_position.y = mouse.position.x;
1.1.1.43 root 3076: if(i < 2) {
3077: mouse.status_alt |= 4 << (i * 2);
3078: }
1.1.1.34 root 3079: mouse.status |= 4 << (i * 2);
1.1.1.14 root 3080: }
3081: }
3082: }
1.1.1.24 root 3083: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.33 root 3084: // update keyboard flags in bios data area
1.1.1.35 root 3085: if(ir[i].Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) {
3086: mem[0x417] |= 0x40;
1.1.1.33 root 3087: } else {
1.1.1.35 root 3088: mem[0x417] &= ~0x40;
1.1.1.33 root 3089: }
1.1.1.35 root 3090: if(ir[i].Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) {
3091: mem[0x417] |= 0x20;
1.1.1.33 root 3092: } else {
1.1.1.35 root 3093: mem[0x417] &= ~0x20;
3094: }
3095: if(ir[i].Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) {
3096: mem[0x417] |= 0x10;
3097: } else {
3098: mem[0x417] &= ~0x10;
1.1.1.33 root 3099: }
3100: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1.1.1.43 root 3101: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3102: mouse.status_alt |= 0x80;
3103: }
1.1.1.33 root 3104: mem[0x417] |= 0x08;
3105: } else {
3106: mem[0x417] &= ~0x08;
3107: }
1.1.1.35 root 3108: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1.1.1.43 root 3109: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3110: mouse.status_alt |= 0x40;
3111: }
1.1.1.35 root 3112: mem[0x417] |= 0x04;
1.1.1.33 root 3113: } else {
1.1.1.35 root 3114: mem[0x417] &= ~0x04;
1.1.1.33 root 3115: }
3116: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1.1.1.43 root 3117: if(mouse.buttons[0].status || mouse.buttons[1].status) {
3118: mouse.status_alt |= 0x20;
3119: }
1.1.1.33 root 3120: if(!(mem[0x417] & 0x03)) {
3121: mem[0x417] |= 0x02; // left shift
3122: }
3123: } else {
3124: mem[0x417] &= ~0x03;
3125: }
1.1.1.35 root 3126: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) {
3127: mem[0x418] |= 0x02;
3128: } else {
3129: mem[0x418] &= ~0x02;
3130: }
3131: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
3132: mem[0x418] |= 0x01;
3133: } else {
3134: mem[0x418] &= ~0x01;
3135: }
1.1.1.33 root 3136:
1.1.1.28 root 3137: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 3138: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.33 root 3139: kbd_status |= 1;
3140:
3141: // update dos key buffer
3142: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
3143: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
3144:
3145: if(ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 3146: // make
1.1.1.24 root 3147: kbd_data &= 0x7f;
3148:
1.1.1.33 root 3149: if(chr == 0x00) {
1.1.1.24 root 3150: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3151: if(scn >= 0x3b && scn <= 0x44) {
3152: scn += 0x68 - 0x3b; // F1 to F10
3153: } else if(scn == 0x57 || scn == 0x58) {
3154: scn += 0x8b - 0x57; // F11 & F12
3155: } else if(scn >= 0x47 && scn <= 0x53) {
3156: scn += 0x97 - 0x47; // edit/arrow clusters
3157: } else if(scn == 0x35) {
3158: scn = 0xa4; // keypad /
3159: }
3160: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3161: if(scn == 0x07) {
3162: chr = 0x1e; // Ctrl+^
3163: } else if(scn == 0x0c) {
3164: chr = 0x1f; // Ctrl+_
3165: } else if(scn >= 0x35 && scn <= 0x58) {
3166: static const UINT8 ctrl_map[] = {
3167: 0x95, // keypad /
3168: 0,
3169: 0x96, // keypad *
3170: 0, 0, 0,
3171: 0x5e, // F1
3172: 0x5f, // F2
3173: 0x60, // F3
3174: 0x61, // F4
3175: 0x62, // F5
3176: 0x63, // F6
3177: 0x64, // F7
3178: 0x65, // F8
3179: 0x66, // F9
3180: 0x67, // F10
3181: 0,
3182: 0,
3183: 0x77, // Home
3184: 0x8d, // Up
3185: 0x84, // PgUp
3186: 0x8e, // keypad -
3187: 0x73, // Left
3188: 0x8f, // keypad center
3189: 0x74, // Right
3190: 0x90, // keyapd +
3191: 0x75, // End
3192: 0x91, // Down
3193: 0x76, // PgDn
3194: 0x92, // Insert
3195: 0x93, // Delete
3196: 0, 0, 0,
3197: 0x89, // F11
3198: 0x8a, // F12
3199: };
3200: scn = ctrl_map[scn - 0x35];
3201: }
3202: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3203: if(scn >= 0x3b && scn <= 0x44) {
3204: scn += 0x54 - 0x3b; // F1 to F10
3205: } else if(scn == 0x57 || scn == 0x58) {
3206: scn += 0x87 - 0x57; // F11 & F12
3207: }
3208: } else if(scn == 0x57 || scn == 0x58) {
3209: scn += 0x85 - 0x57;
3210: }
3211: // ignore shift, ctrl, alt, win and menu keys
3212: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1.1.1.32 root 3213: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3214: #ifdef USE_SERVICE_THREAD
3215: EnterCriticalSection(&key_buf_crit_sect);
3216: #endif
1.1.1.32 root 3217: if(chr == 0) {
3218: key_buf_char->write(0x00);
3219: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
3220: }
3221: key_buf_char->write(chr);
3222: key_buf_scan->write(scn);
1.1.1.35 root 3223: #ifdef USE_SERVICE_THREAD
3224: LeaveCriticalSection(&key_buf_crit_sect);
3225: #endif
1.1.1.24 root 3226: }
3227: }
3228: } else {
3229: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3230: chr = 0;
3231: if(scn >= 0x02 && scn <= 0x0e) {
3232: scn += 0x78 - 0x02; // 1 to 0 - =
3233: }
3234: }
1.1.1.32 root 3235: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3236: #ifdef USE_SERVICE_THREAD
3237: EnterCriticalSection(&key_buf_crit_sect);
3238: #endif
1.1.1.32 root 3239: key_buf_char->write(chr);
3240: key_buf_scan->write(scn);
1.1.1.35 root 3241: #ifdef USE_SERVICE_THREAD
3242: LeaveCriticalSection(&key_buf_crit_sect);
3243: #endif
1.1.1.32 root 3244: }
1.1.1.24 root 3245: }
1.1.1.33 root 3246: } else if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) {
3247: // ctrl-break, ctrl-c
3248: if(scn == 0x46) {
3249: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3250: #ifdef USE_SERVICE_THREAD
3251: EnterCriticalSection(&key_buf_crit_sect);
3252: #endif
1.1.1.33 root 3253: key_buf_char->write(0x00);
3254: key_buf_scan->write(0x00);
1.1.1.35 root 3255: #ifdef USE_SERVICE_THREAD
3256: LeaveCriticalSection(&key_buf_crit_sect);
3257: #endif
1.1.1.33 root 3258: }
3259: ctrl_break_pressed = true;
3260: mem[0x471] = 0x80;
3261: raise_int_1bh = true;
3262: } else {
3263: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3264: #ifdef USE_SERVICE_THREAD
3265: EnterCriticalSection(&key_buf_crit_sect);
3266: #endif
1.1.1.33 root 3267: key_buf_char->write(chr);
3268: key_buf_scan->write(scn);
1.1.1.35 root 3269: #ifdef USE_SERVICE_THREAD
3270: LeaveCriticalSection(&key_buf_crit_sect);
3271: #endif
1.1.1.33 root 3272: }
3273: ctrl_c_pressed = (scn == 0x2e);
3274: }
3275: } else {
3276: // break
3277: kbd_data |= 0x80;
1.1 root 3278: }
1.1.1.24 root 3279: result = key_changed = true;
1.1.1.36 root 3280: // IME may be on and it may causes screen scroll up and cursor position change
3281: cursor_moved = true;
1.1 root 3282: }
3283: }
3284: }
3285: }
1.1.1.35 root 3286: #ifdef USE_SERVICE_THREAD
3287: LeaveCriticalSection(&input_crit_sect);
3288: #endif
1.1.1.24 root 3289: return(result);
1.1.1.8 root 3290: }
3291:
1.1.1.14 root 3292: bool update_key_buffer()
1.1.1.8 root 3293: {
1.1.1.35 root 3294: if(update_console_input()) {
3295: return(true);
3296: }
3297: if(key_buf_char != NULL && key_buf_scan != NULL) {
3298: #ifdef USE_SERVICE_THREAD
3299: EnterCriticalSection(&key_buf_crit_sect);
3300: #endif
3301: bool empty = key_buf_char->empty();
3302: #ifdef USE_SERVICE_THREAD
3303: LeaveCriticalSection(&key_buf_crit_sect);
3304: #endif
3305: if(!empty) return(true);
3306: }
3307: return(false);
1.1.1.8 root 3308: }
3309:
1.1.1.20 root 3310: /* ----------------------------------------------------------------------------
3311: MS-DOS virtual machine
3312: ---------------------------------------------------------------------------- */
3313:
1.1.1.32 root 3314: static const struct {
1.1.1.33 root 3315: char *name;
3316: DWORD lcid;
3317: char *std;
3318: char *dlt;
3319: } tz_table[] = {
3320: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
3321: // 0 GMT Greenwich Mean Time GMT0
3322: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
3323: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
3324: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
3325: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
3326: // 2 FST FDT Fernando De Noronha Std FST2FDT
3327: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3328: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3329: // 3 BST Brazil Standard Time BST3
3330: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
3331: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
3332: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
3333: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
3334: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
3335: // 3 GST Greenland Standard Time GST3
3336: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
3337: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
3338: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
3339: // 4 AST ADT Atlantic Standard Time AST4ADT
3340: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
3341: // 4 WST WDT Western Standard (Brazil) WST4WDT
3342: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
3343: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
3344: // 5 EST EDT Eastern Standard Time EST5EDT
3345: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
3346: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
3347: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
3348: // 5 CST CDT Chile Standard Time CST5CDT
3349: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
3350: // 5 AST ADT Acre Standard Time AST5ADT
3351: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
3352: // 5 CST CDT Cuba Standard Time CST5CDT
3353: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
3354: // 6 CST CDT Central Standard Time CST6CDT
3355: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
3356: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
3357: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
3358: // 6 EST EDT Easter Island Standard EST6EDT
3359: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
3360: // 7 MST MDT Mountain Standard Time MST7MDT
3361: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
3362: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
3363: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
3364: // 8 PST PDT Pacific Standard Time PST8PDT
3365: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
3366: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
3367: // 9 AKS AKD Alaska Standard Time AKS9AKD
3368: // 9 YST YDT Yukon Standard Time YST9YST
3369: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
3370: // 10 HST HDT Hawaii Standard Time HST10HDT
3371: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
3372: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
3373: // 11 SST Samoa Standard Time SST11
3374: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
3375: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
3376: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
3377: // -10 GST Guam Standard Time GST-10
3378: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
3379: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
3380: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
3381: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
3382: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
3383: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
3384: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
3385: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
3386: // -9 JST Japan Standard Time JST-9
3387: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
3388: // -9 KST KDT Korean Standard Time KST-9KDT
3389: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
3390: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
3391: // -8 HKT Hong Kong Time HKT-8
3392: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
3393: // -8 CCT China Coast Time CCT-8
3394: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
3395: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
3396: // -8 SST Singapore Standard Time SST-8
3397: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
3398: // -8 WAS WAD Western Australian Standard WAS-8WAD
3399: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
3400: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
3401: // -7:30 JT Java Standard Time JST-7:30
3402: // -7 NST North Sumatra Time NST-7
3403: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
3404: // -5:30 IST Indian Standard Time IST-5:30
3405: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
3406: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
3407: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
3408: // -3 MSK MSD Moscow Winter Time MSK-3MSD
3409: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
3410: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
3411: // -2 EET Eastern Europe Time EET-2
3412: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
3413: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
3414: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
3415: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
3416: // -2 IST IDT Israel Standard Time IST-2IDT
3417: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
3418: // -1 MEZ MES Middle European Time MEZ-1MES
3419: // -1 SWT SST Swedish Winter Time SWT-1SST
3420: // -1 FWT FST French Winter Time FWT-1FST
3421: // -1 CET CES Central European Time CET-1CES
3422: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
3423: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
3424: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
3425: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
3426: // -1 WAT West African Time WAT-1
3427: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
3428: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
3429: // 0 UTC Universal Coordinated Time UTC0
3430: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
3431: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
3432: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
3433: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
3434: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
3435: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
3436: };
3437:
3438: static const struct {
1.1.1.32 root 3439: UINT16 code;
3440: char *message_english;
3441: char *message_japanese;
3442: } standard_error_table[] = {
3443: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3444: {0x02, "File not found", "�t�@�C����������܂���."},
3445: {0x03, "Path not found", "�p�X��������܂���."},
3446: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3447: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3448: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3449: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3450: {0x08, "Insufficient memory", "������������܂���."},
3451: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3452: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3453: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3454: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3455: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3456: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3457: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3458: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3459: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3460: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3461: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3462: {0x15, "Not ready", "�������ł��Ă��܂���."},
3463: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3464: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3465: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3466: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3467: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3468: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3469: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3470: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3471: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3472: {0x1F, "General failure", "�G���[�ł�."},
3473: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3474: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3475: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3476: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3477: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3478: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3479: {0x26, "Out of input", "���͂��I���܂���."},
3480: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3481: /*
3482: {0x32, "Network request not supported", NULL},
3483: {0x33, "Remote computer not listening", NULL},
3484: {0x34, "Duplicate name on network", NULL},
3485: {0x35, "Network name not found", NULL},
3486: {0x36, "Network busy", NULL},
3487: {0x37, "Network device no longer exists", NULL},
3488: {0x38, "Network BIOS command limit exceeded", NULL},
3489: {0x39, "Network adapter hardware error", NULL},
3490: {0x3A, "Incorrect response from network", NULL},
3491: {0x3B, "Unexpected network error", NULL},
3492: {0x3C, "Incompatible remote adapter", NULL},
3493: {0x3D, "Print queue full", NULL},
3494: {0x3E, "Queue not full", NULL},
3495: {0x3F, "Not enough space to print file", NULL},
3496: {0x40, "Network name was deleted", NULL},
3497: {0x41, "Network: Access denied", NULL},
3498: {0x42, "Network device type incorrect", NULL},
3499: {0x43, "Network name not found", NULL},
3500: {0x44, "Network name limit exceeded", NULL},
3501: {0x45, "Network BIOS session limit exceeded", NULL},
3502: {0x46, "Temporarily paused", NULL},
3503: {0x47, "Network request not accepted", NULL},
3504: {0x48, "Network print/disk redirection paused", NULL},
3505: {0x49, "Network software not installed", NULL},
3506: {0x4A, "Unexpected adapter close", NULL},
3507: */
3508: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
1.1.1.33 root 3509: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
1.1.1.32 root 3510: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3511: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3512: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3513: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3514: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3515: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3516: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3517: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
3518: /*
3519: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3520: {0x65, "Not ready", "�������ł��Ă��܂���."},
3521: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3522: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3523: {0x68, "Door open", "���o�[���܂��Ă��܂���."
3524: */
3525: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3526: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3527: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3528: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3529: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3530: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3531: };
3532:
3533: static const struct {
3534: UINT16 code;
3535: char *message_english;
3536: char *message_japanese;
3537: } param_error_table[] = {
3538: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3539: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3540: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3541: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3542: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3543: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3544: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3545: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3546: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3547: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3548: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3549: };
3550:
3551: static const struct {
3552: UINT16 code;
3553: char *message_english;
3554: char *message_japanese;
3555: } critical_error_table[] = {
3556: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3557: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3558: {0x02, "Not ready", "�������ł��Ă��܂���."},
3559: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3560: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3561: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3562: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3563: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3564: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3565: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3566: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3567: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3568: {0x0C, "General failure", "�G���[�ł�."},
3569: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3570: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3571: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3572: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3573: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3574: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3575: {0x13, "Out of input", "���͂��I���܂���."},
3576: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3577: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3578: };
3579:
1.1.1.20 root 3580: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3581: int msdos_psp_get_file_table(int fd, int psp_seg);
3582: void msdos_putch(UINT8 data);
1.1.1.35 root 3583: #ifdef USE_SERVICE_THREAD
3584: void msdos_putch_tmp(UINT8 data);
3585: #endif
1.1.1.45 root 3586: const char *msdos_short_path(const char *path);
1.1.1.44 root 3587: bool msdos_is_valid_drive(int drv);
3588: bool msdos_is_removable_drive(int drv);
3589: bool msdos_is_cdrom_drive(int drv);
3590: bool msdos_is_remote_drive(int drv);
3591: bool msdos_is_subst_drive(int drv);
1.1.1.20 root 3592:
1.1 root 3593: // process info
3594:
3595: process_t *msdos_process_info_create(UINT16 psp_seg)
3596: {
3597: for(int i = 0; i < MAX_PROCESS; i++) {
3598: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3599: memset(&process[i], 0, sizeof(process_t));
3600: process[i].psp = psp_seg;
3601: return(&process[i]);
3602: }
3603: }
3604: fatalerror("too many processes\n");
3605: return(NULL);
3606: }
3607:
1.1.1.33 root 3608: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error)
1.1 root 3609: {
3610: for(int i = 0; i < MAX_PROCESS; i++) {
3611: if(process[i].psp == psp_seg) {
3612: return(&process[i]);
3613: }
3614: }
1.1.1.33 root 3615: if(show_error) {
3616: fatalerror("invalid psp address\n");
3617: }
1.1 root 3618: return(NULL);
3619: }
3620:
1.1.1.33 root 3621: process_t *msdos_process_info_get(UINT16 psp_seg)
3622: {
3623: return(msdos_process_info_get(psp_seg, true));
3624: }
3625:
1.1.1.23 root 3626: void msdos_sda_update(int psp_seg)
3627: {
3628: sda_t *sda = (sda_t *)(mem + SDA_TOP);
3629:
3630: for(int i = 0; i < MAX_PROCESS; i++) {
3631: if(process[i].psp == psp_seg) {
3632: sda->switchar = process[i].switchar;
3633: sda->current_dta.w.l = process[i].dta.w.l;
3634: sda->current_dta.w.h = process[i].dta.w.h;
3635: sda->current_psp = process[i].psp;
3636: break;
3637: }
3638: }
3639: sda->malloc_strategy = malloc_strategy;
3640: sda->return_code = retval;
3641: sda->current_drive = _getdrive();
3642: }
3643:
1.1.1.13 root 3644: // dta info
3645:
3646: void msdos_dta_info_init()
3647: {
1.1.1.14 root 3648: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 3649: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3650: }
3651: }
3652:
3653: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
3654: {
3655: dtainfo_t *free_dta = NULL;
1.1.1.14 root 3656: for(int i = 0; i < MAX_DTAINFO; i++) {
3657: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
3658: if(free_dta == NULL) {
1.1.1.13 root 3659: free_dta = &dtalist[i];
3660: }
1.1.1.14 root 3661: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 3662: return(&dtalist[i]);
3663: }
3664: }
1.1.1.14 root 3665: if(free_dta) {
1.1.1.13 root 3666: free_dta->psp = psp_seg;
3667: free_dta->dta = dta_laddr;
3668: return(free_dta);
3669: }
3670: fatalerror("too many dta\n");
3671: return(NULL);
3672: }
3673:
3674: void msdos_dta_info_free(UINT16 psp_seg)
3675: {
1.1.1.14 root 3676: for(int i = 0; i < MAX_DTAINFO; i++) {
3677: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 3678: FindClose(dtalist[i].find_handle);
3679: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3680: }
3681: }
3682: }
3683:
1.1 root 3684: void msdos_cds_update(int drv)
3685: {
1.1.1.44 root 3686: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv);
1.1 root 3687:
1.1.1.44 root 3688: memset(cds, 0, 88);
3689:
3690: if(msdos_is_valid_drive(drv)) {
3691: char path[MAX_PATH];
3692: if(msdos_is_remote_drive(drv)) {
3693: cds->drive_attrib = 0xc000; // network drive
3694: } else if(msdos_is_subst_drive(drv)) {
3695: cds->drive_attrib = 0x5000; // subst drive
3696: } else {
3697: cds->drive_attrib = 0x4000; // physical drive
3698: }
3699: if(_getdcwd(drv + 1, path, MAX_PATH) != NULL) {
3700: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path));
3701: }
3702: }
3703: if(cds->path_name[0] == '\0') {
3704: sprintf(cds->path_name, "%c:\\", 'A' + drv);
3705: }
3706: cds->dpb_ptr.w.h = DPB_TOP >> 4;
3707: cds->dpb_ptr.w.l = sizeof(dpb_t) * drv;
3708: cds->word_1 = cds->word_2 = 0xffff;
3709: cds->word_3 = 0xffff; // stored user data from INT 21/AX=5F03h if this is network drive
3710: cds->bs_offset = 2;
3711: }
3712:
1.1.1.45 root 3713: void msdos_cds_update(int drv, const char *path)
1.1.1.44 root 3714: {
3715: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv);
3716:
3717: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path));
1.1 root 3718: }
3719:
1.1.1.17 root 3720: // nls information tables
3721:
3722: // uppercase table (func 6502h)
3723: void msdos_upper_table_update()
3724: {
3725: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3726: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3727: UINT8 c[4];
1.1.1.33 root 3728: *(UINT32 *)c = 0; // reset internal conversion state
3729: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.17 root 3730: c[0] = 0x80 + i;
3731: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
3732: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3733: }
3734: }
3735:
1.1.1.23 root 3736: // lowercase table (func 6503h)
3737: void msdos_lower_table_update()
3738: {
3739: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
3740: for(unsigned i = 0; i < 0x80; ++i) {
3741: UINT8 c[4];
1.1.1.33 root 3742: *(UINT32 *)c = 0; // reset internal conversion state
3743: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.23 root 3744: c[0] = 0x80 + i;
3745: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
3746: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3747: }
3748: }
3749:
1.1.1.17 root 3750: // filename uppercase table (func 6504h)
3751: void msdos_filename_upper_table_init()
3752: {
3753: // depended on (file)system, not on active codepage
3754: // temporary solution: just filling data
3755: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3756: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3757: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
3758: }
3759: }
3760:
3761: // filaname terminator table (func 6505h)
3762: void msdos_filename_terminator_table_init()
3763: {
3764: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
3765: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
3766:
3767: data[2] = 1; // marker? (permissible character value)
3768: data[3] = 0x00; // 00h...FFh
3769: data[4] = 0xff;
3770: data[5] = 0; // marker? (excluded character)
3771: data[6] = 0x00; // 00h...20h
3772: data[7] = 0x20;
3773: data[8] = 2; // marker? (illegal characters for filename)
3774: data[9] = (UINT8)strlen(illegal_chars);
3775: memcpy(data + 10, illegal_chars, data[9]);
3776:
3777: // total length
3778: *(UINT16 *)data = (10 - 2) + data[9];
3779: }
3780:
3781: // collating table (func 6506h)
3782: void msdos_collating_table_update()
3783: {
3784: // temporary solution: just filling data
3785: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 3786: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 3787: mem[COLLATING_TABLE_TOP + 2 + i] = i;
3788: }
3789: }
3790:
1.1 root 3791: // dbcs
3792:
3793: void msdos_dbcs_table_update()
3794: {
3795: UINT8 dbcs_data[DBCS_SIZE];
3796: memset(dbcs_data, 0, sizeof(dbcs_data));
3797:
3798: CPINFO info;
3799: GetCPInfo(active_code_page, &info);
3800:
3801: if(info.MaxCharSize != 1) {
3802: for(int i = 0;; i += 2) {
3803: UINT8 lo = info.LeadByte[i + 0];
3804: UINT8 hi = info.LeadByte[i + 1];
3805: dbcs_data[2 + i + 0] = lo;
3806: dbcs_data[2 + i + 1] = hi;
3807: if(lo == 0 && hi == 0) {
3808: dbcs_data[0] = i + 2;
3809: break;
3810: }
3811: }
3812: } else {
3813: dbcs_data[0] = 2; // ???
3814: }
3815: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
3816: }
3817:
1.1.1.17 root 3818: void msdos_dbcs_table_finish()
3819: {
1.1.1.32 root 3820: if(system_code_page != _getmbcp()) {
1.1.1.17 root 3821: _setmbcp(system_code_page);
3822: }
1.1.1.32 root 3823: if(console_code_page != GetConsoleCP()) {
3824: SetConsoleCP(console_code_page);
3825: SetConsoleOutputCP(console_code_page);
3826: }
1.1.1.17 root 3827: }
3828:
3829: void msdos_nls_tables_init()
1.1 root 3830: {
1.1.1.32 root 3831: active_code_page = console_code_page = GetConsoleCP();
3832: system_code_page = _getmbcp();
3833:
3834: if(active_code_page != system_code_page) {
3835: if(_setmbcp(active_code_page) != 0) {
3836: active_code_page = system_code_page;
3837: }
3838: }
3839:
1.1.1.17 root 3840: msdos_upper_table_update();
1.1.1.23 root 3841: msdos_lower_table_update();
1.1.1.17 root 3842: msdos_filename_terminator_table_init();
3843: msdos_filename_upper_table_init();
3844: msdos_collating_table_update();
1.1 root 3845: msdos_dbcs_table_update();
3846: }
3847:
1.1.1.17 root 3848: void msdos_nls_tables_update()
1.1 root 3849: {
1.1.1.17 root 3850: msdos_dbcs_table_update();
3851: msdos_upper_table_update();
1.1.1.23 root 3852: msdos_lower_table_update();
3853: // msdos_collating_table_update();
1.1 root 3854: }
3855:
3856: int msdos_lead_byte_check(UINT8 code)
3857: {
3858: UINT8 *dbcs_table = mem + DBCS_TABLE;
3859:
3860: for(int i = 0;; i += 2) {
3861: UINT8 lo = dbcs_table[i + 0];
3862: UINT8 hi = dbcs_table[i + 1];
3863: if(lo == 0 && hi == 0) {
3864: break;
3865: }
3866: if(lo <= code && code <= hi) {
3867: return(1);
3868: }
3869: }
3870: return(0);
3871: }
3872:
1.1.1.20 root 3873: int msdos_ctrl_code_check(UINT8 code)
3874: {
1.1.1.22 root 3875: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 3876: }
3877:
1.1.1.36 root 3878: int msdos_kanji_2nd_byte_check(UINT8 *buf, int n)
3879: {
3880: int is_kanji_1st = 0;
3881: int is_kanji_2nd = 0;
3882:
3883: for(int p = 0;; p++) {
3884: if(is_kanji_1st) {
3885: is_kanji_1st = 0;
3886: is_kanji_2nd = 1;
3887: } else if(msdos_lead_byte_check(buf[p])) {
3888: is_kanji_1st = 1;
3889: }
3890: if(p == n) {
3891: return(is_kanji_2nd);
3892: }
3893: is_kanji_2nd = 0;
3894: }
3895: }
3896:
1.1 root 3897: // file control
3898:
1.1.1.45 root 3899: const char *msdos_remove_double_quote(const char *path)
1.1.1.14 root 3900: {
3901: static char tmp[MAX_PATH];
3902:
3903: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1.1.1.45 root 3904: memset(tmp, 0, sizeof(tmp));
1.1.1.14 root 3905: memcpy(tmp, path + 1, strlen(path) - 2);
3906: } else {
3907: strcpy(tmp, path);
3908: }
3909: return(tmp);
3910: }
3911:
1.1.1.45 root 3912: const char *msdos_remove_end_separator(const char *path)
1.1.1.32 root 3913: {
3914: static char tmp[MAX_PATH];
3915:
3916: strcpy(tmp, path);
1.1.1.45 root 3917:
3918: // for example "C:\" case, the end separator should not be removed
3919: if(strlen(tmp) > 3 && tmp[strlen(tmp) - 1] == '\\') {
3920: tmp[strlen(tmp) - 1] = '\0';
1.1.1.32 root 3921: }
3922: return(tmp);
3923: }
3924:
1.1.1.45 root 3925: const char *msdos_combine_path(const char *dir, const char *file)
1.1.1.14 root 3926: {
3927: static char tmp[MAX_PATH];
1.1.1.45 root 3928: const char *tmp_dir = msdos_remove_double_quote(dir);
1.1.1.14 root 3929:
3930: if(strlen(tmp_dir) == 0) {
3931: strcpy(tmp, file);
3932: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
3933: sprintf(tmp, "%s%s", tmp_dir, file);
3934: } else {
3935: sprintf(tmp, "%s\\%s", tmp_dir, file);
3936: }
3937: return(tmp);
3938: }
3939:
1.1.1.45 root 3940: const char *msdos_trimmed_path(const char *path, int lfn)
1.1 root 3941: {
3942: static char tmp[MAX_PATH];
3943:
3944: if(lfn) {
3945: strcpy(tmp, path);
3946: } else {
3947: // remove space in the path
1.1.1.45 root 3948: const char *src = path;
3949: char *dst = tmp;
1.1 root 3950:
3951: while(*src != '\0') {
3952: if(msdos_lead_byte_check(*src)) {
3953: *dst++ = *src++;
3954: *dst++ = *src++;
3955: } else if(*src != ' ') {
3956: *dst++ = *src++;
3957: } else {
3958: src++; // skip space
3959: }
3960: }
3961: *dst = '\0';
3962: }
1.1.1.14 root 3963: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
3964: // redirect C:\COMMAND.COM to comspec_path
3965: strcpy(tmp, comspec_path);
3966: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
3967: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
3968: static int root_drive_protected = -1;
3969: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
3970: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
3971:
3972: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
3973: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
3974: strcpy(name, name_temp);
3975: name_temp[0] = '\0';
3976:
3977: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
3978: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
3979: if(root_drive_protected == -1) {
3980: FILE *fp = NULL;
3981:
3982: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
3983: root_drive_protected = 1;
3984: try {
3985: if((fp = fopen(temp, "w")) != NULL) {
3986: if(fprintf(fp, "TEST") == 4) {
3987: root_drive_protected = 0;
3988: }
3989: }
3990: } catch(...) {
3991: }
3992: if(fp != NULL) {
3993: fclose(fp);
3994: }
3995: if(_access(temp, 0) == 0) {
3996: remove(temp);
3997: }
3998: }
3999: if(root_drive_protected == 1) {
4000: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
4001: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
4002: strcpy(tmp, msdos_combine_path(temp, name));
4003: }
4004: }
4005: }
4006: }
4007: }
1.1 root 4008: return(tmp);
4009: }
4010:
1.1.1.45 root 4011: const char *msdos_get_multiple_short_path(const char *src)
1.1.1.28 root 4012: {
1.1.1.32 root 4013: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 4014: static char env_path[ENV_SIZE];
4015: char tmp[ENV_SIZE], *token;
4016:
4017: memset(env_path, 0, sizeof(env_path));
4018: strcpy(tmp, src);
4019: token = my_strtok(tmp, ";");
4020:
4021: while(token != NULL) {
4022: if(token[0] != '\0') {
1.1.1.45 root 4023: const char *path = msdos_remove_double_quote(token);
4024: char short_path[MAX_PATH];
1.1.1.32 root 4025: if(path != NULL && strlen(path) != 0) {
4026: if(env_path[0] != '\0') {
4027: strcat(env_path, ";");
4028: }
1.1.1.28 root 4029: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32 root 4030: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 4031: } else {
4032: my_strupr(short_path);
1.1.1.32 root 4033: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 4034: }
4035: }
4036: }
4037: token = my_strtok(NULL, ";");
4038: }
4039: return(env_path);
4040: }
4041:
1.1.1.45 root 4042: bool match(const char *text, const char *pattern)
1.1 root 4043: {
1.1.1.24 root 4044: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 4045: switch(*pattern) {
1.1 root 4046: case '\0':
4047: return !*text;
4048: case '*':
1.1.1.14 root 4049: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 4050: case '?':
4051: return *text && match(text + 1, pattern + 1);
4052: default:
4053: return (*text == *pattern) && match(text + 1, pattern + 1);
4054: }
4055: }
4056:
1.1.1.45 root 4057: bool msdos_match_volume_label(const char *path, const char *volume)
1.1 root 4058: {
1.1.1.45 root 4059: const char *p = NULL;
1.1 root 4060:
1.1.1.14 root 4061: if(!*volume) {
4062: return false;
4063: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 4064: return msdos_match_volume_label(p + 1, volume);
4065: } else if((p = my_strchr(path, '\\')) != NULL) {
4066: return msdos_match_volume_label(p + 1, volume);
4067: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 4068: char tmp[MAX_PATH];
4069: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
4070: return match(volume, tmp);
1.1 root 4071: } else {
4072: return match(volume, path);
4073: }
4074: }
4075:
1.1.1.45 root 4076: const char *msdos_fcb_path(fcb_t *fcb)
1.1 root 4077: {
4078: static char tmp[MAX_PATH];
4079: char name[9], ext[4];
4080:
4081: memset(name, 0, sizeof(name));
4082: memcpy(name, fcb->file_name, 8);
4083: strcpy(name, msdos_trimmed_path(name, 0));
4084:
4085: memset(ext, 0, sizeof(ext));
4086: memcpy(ext, fcb->file_name + 8, 3);
4087: strcpy(ext, msdos_trimmed_path(ext, 0));
4088:
4089: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
4090: strcpy(name, "*");
4091: }
4092: if(ext[0] == '\0') {
4093: strcpy(tmp, name);
4094: } else {
4095: if(strcmp(ext, "???") == 0) {
4096: strcpy(ext, "*");
4097: }
4098: sprintf(tmp, "%s.%s", name, ext);
4099: }
4100: return(tmp);
4101: }
4102:
1.1.1.45 root 4103: void msdos_set_fcb_path(fcb_t *fcb, const char *path)
1.1 root 4104: {
4105: char *ext = my_strchr(path, '.');
4106:
4107: memset(fcb->file_name, 0x20, 8 + 3);
4108: if(ext != NULL && path[0] != '.') {
4109: *ext = '\0';
4110: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
4111: }
4112: memcpy(fcb->file_name, path, strlen(path));
4113: }
4114:
1.1.1.45 root 4115: const char *msdos_short_path(const char *path)
1.1 root 4116: {
4117: static char tmp[MAX_PATH];
4118:
1.1.1.24 root 4119: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
4120: strcpy(tmp, path);
4121: }
1.1 root 4122: my_strupr(tmp);
4123: return(tmp);
4124: }
4125:
1.1.1.45 root 4126: const char *msdos_short_name(WIN32_FIND_DATA *fd)
1.1.1.13 root 4127: {
4128: static char tmp[MAX_PATH];
1.1.1.45 root 4129:
1.1.1.14 root 4130: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4131: strcpy(tmp, fd->cAlternateFileName);
4132: } else {
4133: strcpy(tmp, fd->cFileName);
4134: }
4135: my_strupr(tmp);
4136: return(tmp);
4137: }
4138:
1.1.1.45 root 4139: const char *msdos_short_full_path(const char *path)
1.1 root 4140: {
4141: static char tmp[MAX_PATH];
4142: char full[MAX_PATH], *name;
4143:
1.1.1.14 root 4144: // Full works with non-existent files, but Short does not
1.1 root 4145: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 4146: *tmp = '\0';
4147: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
4148: name[-1] = '\0';
4149: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
4150: if(len == 0) {
4151: strcpy(tmp, full);
4152: } else {
4153: tmp[len++] = '\\';
4154: strcpy(tmp + len, name);
4155: }
4156: }
1.1 root 4157: my_strupr(tmp);
4158: return(tmp);
4159: }
4160:
1.1.1.45 root 4161: const char *msdos_short_full_dir(const char *path)
1.1 root 4162: {
4163: static char tmp[MAX_PATH];
4164: char full[MAX_PATH], *name;
4165:
4166: GetFullPathName(path, MAX_PATH, full, &name);
4167: name[-1] = '\0';
1.1.1.24 root 4168: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
4169: strcpy(tmp, full);
4170: }
1.1 root 4171: my_strupr(tmp);
4172: return(tmp);
4173: }
4174:
1.1.1.45 root 4175: const char *msdos_local_file_path(const char *path, int lfn)
1.1 root 4176: {
1.1.1.45 root 4177: static char trimmed[MAX_PATH];
4178:
4179: strcpy(trimmed, msdos_trimmed_path(path, lfn));
1.1.1.14 root 4180: #if 0
4181: // I have forgotten the reason of this routine... :-(
1.1 root 4182: if(_access(trimmed, 0) != 0) {
4183: process_t *process = msdos_process_info_get(current_psp);
4184: static char tmp[MAX_PATH];
4185:
4186: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
4187: if(_access(tmp, 0) == 0) {
4188: return(tmp);
4189: }
4190: }
1.1.1.14 root 4191: #endif
1.1 root 4192: return(trimmed);
4193: }
4194:
1.1.1.45 root 4195: bool msdos_is_device_path(const char *path)
1.1.1.11 root 4196: {
4197: char full[MAX_PATH], *name;
4198:
1.1.1.24 root 4199: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4200: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4201: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4202: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4203: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4204: _stricmp(full, "\\\\.\\COM1") == 0 ||
4205: _stricmp(full, "\\\\.\\COM2") == 0 ||
4206: _stricmp(full, "\\\\.\\COM3") == 0 ||
4207: _stricmp(full, "\\\\.\\COM4") == 0 ||
4208: _stricmp(full, "\\\\.\\COM5") == 0 ||
4209: _stricmp(full, "\\\\.\\COM6") == 0 ||
4210: _stricmp(full, "\\\\.\\COM7") == 0 ||
4211: _stricmp(full, "\\\\.\\COM8") == 0 ||
4212: _stricmp(full, "\\\\.\\COM9") == 0 ||
4213: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4214: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4215: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4216: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4217: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4218: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4219: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4220: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4221: _stricmp(full, "\\\\.\\LPT9") == 0) {
4222: return(true);
4223: } else if(name != NULL) {
4224: if(_stricmp(name, "CLOCK$" ) == 0 ||
4225: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 4226: _stricmp(name, "EMMXXXX0") == 0 ||
1.1.1.43 root 4227: // _stricmp(name, "SCSIMGR$") == 0 ||
1.1.1.30 root 4228: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 4229: return(true);
4230: }
4231: }
1.1.1.24 root 4232: }
4233: return(false);
1.1.1.11 root 4234: }
4235:
1.1.1.45 root 4236: bool msdos_is_con_path(const char *path)
1.1.1.8 root 4237: {
1.1.1.14 root 4238: char full[MAX_PATH], *name;
1.1.1.8 root 4239:
1.1.1.24 root 4240: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4241: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 4242: }
4243: return(false);
4244: }
4245:
1.1.1.45 root 4246: int msdos_is_comm_path(const char *path)
1.1.1.24 root 4247: {
4248: char full[MAX_PATH], *name;
4249:
4250: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4251: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4252: return(1);
4253: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4254: return(2);
4255: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4256: return(3);
4257: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4258: return(4);
1.1.1.24 root 4259: }
4260: }
1.1.1.29 root 4261: return(0);
4262: }
4263:
1.1.1.45 root 4264: void msdos_set_comm_params(int sio_port, const char *path)
1.1.1.37 root 4265: {
4266: // COM1:{110,150,300,600,1200,2400,4800,9600},{N,O,E,M,S},{8,7,6,5},{1,1.5,2}
1.1.1.45 root 4267: const char *p = NULL;
1.1.1.37 root 4268:
4269: if((p = strstr(path, ":")) != NULL) {
4270: UINT8 selector = sio_read(sio_port - 1, 3);
4271:
4272: // baud rate
4273: int baud = max(110, min(9600, atoi(p + 1)));
4274: UINT16 divisor = 115200 / baud;
4275:
4276: if((p = strstr(p + 1, ",")) != NULL) {
4277: // parity
4278: if(p[1] == 'N' || p[1] == 'n') {
4279: selector = (selector & ~0x38) | 0x00;
4280: } else if(p[1] == 'O' || p[1] == 'o') {
4281: selector = (selector & ~0x38) | 0x08;
4282: } else if(p[1] == 'E' || p[1] == 'e') {
4283: selector = (selector & ~0x38) | 0x18;
4284: } else if(p[1] == 'M' || p[1] == 'm') {
4285: selector = (selector & ~0x38) | 0x28;
4286: } else if(p[1] == 'S' || p[1] == 's') {
4287: selector = (selector & ~0x38) | 0x38;
4288: }
4289: if((p = strstr(p + 1, ",")) != NULL) {
4290: // word length
4291: if(p[1] == '8') {
4292: selector = (selector & ~0x03) | 0x03;
4293: } else if(p[1] == '7') {
4294: selector = (selector & ~0x03) | 0x02;
4295: } else if(p[1] == '6') {
4296: selector = (selector & ~0x03) | 0x01;
4297: } else if(p[1] == '5') {
4298: selector = (selector & ~0x03) | 0x00;
4299: }
4300: if((p = strstr(p + 1, ",")) != NULL) {
4301: // stop bits
4302: float bits = atof(p + 1);
4303: if(bits > 1.0F) {
4304: selector |= 0x04;
4305: } else {
4306: selector &= ~0x04;
4307: }
4308: }
4309: }
4310: }
4311: sio_write(sio_port - 1, 3, selector | 0x80);
4312: sio_write(sio_port - 1, 0, divisor & 0xff);
4313: sio_write(sio_port - 1, 1, divisor >> 8);
4314: sio_write(sio_port - 1, 3, selector);
4315: }
4316: }
4317:
1.1.1.45 root 4318: int msdos_is_prn_path(const char *path)
1.1.1.30 root 4319: {
4320: char full[MAX_PATH], *name;
4321:
4322: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4323: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4324: return(1);
4325: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4326: return(1);
4327: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4328: return(2);
4329: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4330: return(3);
4331: }
4332: }
4333: return(0);
4334: }
4335:
1.1.1.44 root 4336: bool msdos_is_valid_drive(int drv)
4337: {
4338: return(drv >= 0 && drv < 26 && (GetLogicalDrives() & (1 << drv)) != 0);
4339: }
4340:
4341: bool msdos_is_removable_drive(int drv)
4342: {
4343: char volume[] = "A:\\";
4344:
4345: volume[0] = 'A' + drv;
4346:
4347: return(GetDriveType(volume) == DRIVE_REMOVABLE);
4348: }
4349:
4350: bool msdos_is_cdrom_drive(int drv)
4351: {
4352: char volume[] = "A:\\";
4353:
4354: volume[0] = 'A' + drv;
4355:
4356: return(GetDriveType(volume) == DRIVE_CDROM);
4357: }
4358:
4359: bool msdos_is_remote_drive(int drv)
4360: {
4361: char volume[] = "A:\\";
4362:
4363: volume[0] = 'A' + drv;
4364:
4365: return(GetDriveType(volume) == DRIVE_REMOTE);
4366: }
4367:
4368: bool msdos_is_subst_drive(int drv)
4369: {
4370: char device[] = "A:", path[MAX_PATH];
4371:
4372: device[0] = 'A' + drv;
4373:
4374: if(QueryDosDevice(device, path, MAX_PATH)) {
4375: if(strncmp(path, "\\??\\", 4) == 0) {
4376: return(true);
4377: }
4378: }
4379: return(false);
4380: }
4381:
1.1.1.45 root 4382: bool msdos_is_existing_file(const char *path)
1.1.1.24 root 4383: {
4384: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4385: WIN32_FIND_DATA FindData;
4386: HANDLE hFind;
4387:
4388: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
4389: FindClose(hFind);
4390: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
4391: }
4392: return(false);
1.1.1.8 root 4393: }
4394:
1.1.1.45 root 4395: const char *msdos_search_command_com(const char *command_path, const char *env_path)
1.1.1.9 root 4396: {
4397: static char tmp[MAX_PATH];
1.1.1.28 root 4398: char path[ENV_SIZE], *file_name;
1.1.1.9 root 4399:
1.1.1.28 root 4400: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 4401: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
4402: sprintf(file_name, "COMMAND.COM");
4403: if(_access(tmp, 0) == 0) {
4404: return(tmp);
4405: }
4406: }
1.1.1.28 root 4407:
4408: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 4409: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
4410: sprintf(file_name, "COMMAND.COM");
4411: if(_access(tmp, 0) == 0) {
4412: return(tmp);
4413: }
4414: }
1.1.1.28 root 4415:
4416: // check if COMMAND.COM is in the current directory
1.1.1.9 root 4417: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4418: if(_access(tmp, 0) == 0) {
4419: return(tmp);
4420: }
4421: }
1.1.1.28 root 4422:
4423: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4424: strcpy(path, env_path);
4425: char *token = my_strtok(path, ";");
1.1.1.9 root 4426: while(token != NULL) {
1.1.1.14 root 4427: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 4428: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4429: if(_access(tmp, 0) == 0) {
4430: return(tmp);
4431: }
4432: }
4433: token = my_strtok(NULL, ";");
4434: }
4435: return(NULL);
4436: }
4437:
1.1.1.14 root 4438: int msdos_drive_number(const char *path)
1.1 root 4439: {
4440: char tmp[MAX_PATH], *name;
4441:
1.1.1.45 root 4442: if(GetFullPathName(path, MAX_PATH, tmp, &name) >= 2 && tmp[1] == ':') {
4443: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4444: return(tmp[0] - 'a');
4445: } else if(tmp[0] >= 'A' && tmp[0] <= 'Z') {
4446: return(tmp[0] - 'A');
4447: }
1.1 root 4448: }
1.1.1.45 root 4449: // return(msdos_drive_number("."));
4450: return(_getdrive() - 1);
1.1 root 4451: }
4452:
1.1.1.45 root 4453: const char *msdos_volume_label(const char *path)
1.1 root 4454: {
4455: static char tmp[MAX_PATH];
4456: char volume[] = "A:\\";
4457:
4458: if(path[1] == ':') {
4459: volume[0] = path[0];
4460: } else {
4461: volume[0] = 'A' + _getdrive() - 1;
4462: }
4463: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4464: memset(tmp, 0, sizeof(tmp));
4465: }
4466: return(tmp);
4467: }
4468:
1.1.1.45 root 4469: const char *msdos_short_volume_label(const char *label)
1.1 root 4470: {
4471: static char tmp[(8 + 1 + 3) + 1];
1.1.1.45 root 4472: const char *src = label;
1.1 root 4473: int remain = strlen(label);
4474: char *dst_n = tmp;
4475: char *dst_e = tmp + 9;
4476:
4477: strcpy(tmp, " . ");
4478: for(int i = 0; i < 8 && remain > 0; i++) {
4479: if(msdos_lead_byte_check(*src)) {
4480: if(++i == 8) {
4481: break;
4482: }
4483: *dst_n++ = *src++;
4484: remain--;
4485: }
4486: *dst_n++ = *src++;
4487: remain--;
4488: }
4489: if(remain > 0) {
4490: for(int i = 0; i < 3 && remain > 0; i++) {
4491: if(msdos_lead_byte_check(*src)) {
4492: if(++i == 3) {
4493: break;
4494: }
4495: *dst_e++ = *src++;
4496: remain--;
4497: }
4498: *dst_e++ = *src++;
4499: remain--;
4500: }
4501: *dst_e = '\0';
4502: } else {
4503: *dst_n = '\0';
4504: }
4505: my_strupr(tmp);
4506: return(tmp);
4507: }
4508:
1.1.1.13 root 4509: errno_t msdos_maperr(unsigned long oserrno)
4510: {
4511: _doserrno = oserrno;
1.1.1.14 root 4512: switch(oserrno) {
1.1.1.13 root 4513: case ERROR_FILE_NOT_FOUND: // 2
4514: case ERROR_PATH_NOT_FOUND: // 3
4515: case ERROR_INVALID_DRIVE: // 15
4516: case ERROR_NO_MORE_FILES: // 18
4517: case ERROR_BAD_NETPATH: // 53
4518: case ERROR_BAD_NET_NAME: // 67
4519: case ERROR_BAD_PATHNAME: // 161
4520: case ERROR_FILENAME_EXCED_RANGE: // 206
4521: return ENOENT;
4522: case ERROR_TOO_MANY_OPEN_FILES: // 4
4523: return EMFILE;
4524: case ERROR_ACCESS_DENIED: // 5
4525: case ERROR_CURRENT_DIRECTORY: // 16
4526: case ERROR_NETWORK_ACCESS_DENIED: // 65
4527: case ERROR_CANNOT_MAKE: // 82
4528: case ERROR_FAIL_I24: // 83
4529: case ERROR_DRIVE_LOCKED: // 108
4530: case ERROR_SEEK_ON_DEVICE: // 132
4531: case ERROR_NOT_LOCKED: // 158
4532: case ERROR_LOCK_FAILED: // 167
4533: return EACCES;
4534: case ERROR_INVALID_HANDLE: // 6
4535: case ERROR_INVALID_TARGET_HANDLE: // 114
4536: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4537: return EBADF;
4538: case ERROR_ARENA_TRASHED: // 7
4539: case ERROR_NOT_ENOUGH_MEMORY: // 8
4540: case ERROR_INVALID_BLOCK: // 9
4541: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4542: return ENOMEM;
4543: case ERROR_BAD_ENVIRONMENT: // 10
4544: return E2BIG;
4545: case ERROR_BAD_FORMAT: // 11
4546: return ENOEXEC;
4547: case ERROR_NOT_SAME_DEVICE: // 17
4548: return EXDEV;
4549: case ERROR_FILE_EXISTS: // 80
4550: case ERROR_ALREADY_EXISTS: // 183
4551: return EEXIST;
4552: case ERROR_NO_PROC_SLOTS: // 89
4553: case ERROR_MAX_THRDS_REACHED: // 164
4554: case ERROR_NESTING_NOT_ALLOWED: // 215
4555: return EAGAIN;
4556: case ERROR_BROKEN_PIPE: // 109
4557: return EPIPE;
4558: case ERROR_DISK_FULL: // 112
4559: return ENOSPC;
4560: case ERROR_WAIT_NO_CHILDREN: // 128
4561: case ERROR_CHILD_NOT_COMPLETE: // 129
4562: return ECHILD;
4563: case ERROR_DIR_NOT_EMPTY: // 145
4564: return ENOTEMPTY;
4565: }
1.1.1.14 root 4566: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 4567: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4568: return EACCES;
4569: }
1.1.1.14 root 4570: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 4571: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4572: return ENOEXEC;
4573: }
4574: return EINVAL;
4575: }
4576:
1.1.1.45 root 4577: int msdos_open(const char *path, int oflag)
1.1.1.13 root 4578: {
1.1.1.14 root 4579: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.45 root 4580: return(_open(path, oflag));
1.1.1.13 root 4581: }
1.1.1.14 root 4582:
4583: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 4584: DWORD disposition;
1.1.1.14 root 4585: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4586: default:
1.1.1.13 root 4587: case _O_EXCL:
4588: disposition = OPEN_EXISTING;
4589: break;
4590: case _O_CREAT:
4591: disposition = OPEN_ALWAYS;
4592: break;
4593: case _O_CREAT | _O_EXCL:
4594: case _O_CREAT | _O_TRUNC | _O_EXCL:
4595: disposition = CREATE_NEW;
4596: break;
4597: case _O_TRUNC:
4598: case _O_TRUNC | _O_EXCL:
4599: disposition = TRUNCATE_EXISTING;
4600: break;
4601: case _O_CREAT | _O_TRUNC:
4602: disposition = CREATE_ALWAYS;
4603: break;
4604: }
1.1.1.14 root 4605:
1.1.1.45 root 4606: HANDLE h = CreateFile(path, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1.1.1.13 root 4607: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4608: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4609: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4610: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4611: // Retry without FILE_WRITE_ATTRIBUTES.
1.1.1.45 root 4612: h = CreateFile(path, GENERIC_READ,
1.1.1.13 root 4613: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4614: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4615: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4616: errno = msdos_maperr(GetLastError());
1.1.1.45 root 4617: return(-1);
1.1.1.13 root 4618: }
4619: }
1.1.1.14 root 4620:
1.1.1.13 root 4621: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 4622: if(fd == -1) {
1.1.1.13 root 4623: CloseHandle(h);
4624: }
1.1.1.45 root 4625: return(fd);
4626: }
4627:
4628: int msdos_open_device(const char *path, int oflag, int *sio_port, int *lpt_port)
4629: {
4630: int fd = -1;
4631:
4632: *sio_port = *lpt_port = 0;
4633:
4634: if(msdos_is_con_path(path)) {
4635: // MODE.COM opens CON device with read/write mode :-(
4636: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) == _O_RDWR) {
4637: oflag &= ~(_O_RDONLY | _O_WRONLY | _O_RDWR);
4638: oflag |= _O_RDONLY;
4639: }
4640: if((fd = msdos_open("CON", oflag)) == -1) {
4641: // fd = msdos_open("NUL", oflag);
4642: }
4643: } else if((*sio_port = msdos_is_comm_path(path)) != 0) {
4644: fd = msdos_open("NUL", oflag);
4645: msdos_set_comm_params(*sio_port, path);
4646: } else if((*lpt_port = msdos_is_prn_path(path)) != 0) {
4647: fd = msdos_open("NUL", oflag);
4648: } else if(msdos_is_device_path(path)) {
4649: fd = msdos_open("NUL", oflag);
4650: // } else if(oflag & _O_CREAT) {
4651: // fd = _open(path, oflag, _S_IREAD | _S_IWRITE);
4652: // } else {
4653: // fd = _open(path, oflag);
4654: }
4655: return(fd);
4656: }
4657:
4658: UINT16 msdos_device_info(const char *path)
4659: {
4660: if(msdos_is_con_path(path)) {
4661: return(0x80d3);
4662: } else if(msdos_is_comm_path(path)) {
4663: return(0x80a0);
4664: } else if(msdos_is_prn_path(path)) {
4665: // return(0xa8c0);
4666: return(0x80a0);
4667: } else if(msdos_is_device_path(path)) {
4668: if(strstr(path, "EMMXXXX0") != NULL) {
4669: return(0xc0c0);
4670: } else if(strstr(path, "MSCD001") != NULL) {
4671: return(0xc880);
4672: } else {
4673: return(0x8084);
4674: }
4675: } else {
4676: return(msdos_drive_number(path));
4677: }
1.1.1.13 root 4678: }
4679:
1.1.1.37 root 4680: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg, int sio_port, int lpt_port)
1.1 root 4681: {
4682: static int id = 0;
4683: char full[MAX_PATH], *name;
4684:
4685: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4686: strcpy(file_handler[fd].path, full);
4687: } else {
4688: strcpy(file_handler[fd].path, path);
4689: }
1.1.1.14 root 4690: // isatty makes no distinction between CON & NUL
4691: // GetFileSize fails on CON, succeeds on NUL
4692: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
1.1.1.45 root 4693: if(info == 0x80d3) {
4694: info = 0x8084;
4695: }
1.1.1.14 root 4696: atty = 0;
4697: } else if(!atty && info == 0x80d3) {
1.1.1.45 root 4698: // info = msdos_drive_number(".");
4699: info = msdos_drive_number(path);
1.1.1.14 root 4700: }
1.1 root 4701: file_handler[fd].valid = 1;
4702: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1.1.1.37 root 4703: file_handler[fd].atty = (sio_port == 0 && lpt_port == 0) ? atty : 0;
1.1 root 4704: file_handler[fd].mode = mode;
4705: file_handler[fd].info = info;
4706: file_handler[fd].psp = psp_seg;
1.1.1.37 root 4707: file_handler[fd].sio_port = sio_port;
4708: file_handler[fd].lpt_port = lpt_port;
1.1.1.21 root 4709:
4710: // init system file table
4711: if(fd < 20) {
4712: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
4713:
4714: memset(sft, 0, 0x3b);
4715:
4716: *(UINT16 *)(sft + 0x00) = 1;
4717: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
4718: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
4719: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
4720:
4721: if(!(file_handler[fd].info & 0x80)) {
4722: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
4723: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
4724:
4725: FILETIME time, local;
4726: HANDLE hHandle;
4727: WORD dos_date = 0, dos_time = 0;
4728: DWORD file_size = 0;
4729: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
4730: if(GetFileTime(hHandle, NULL, NULL, &time)) {
4731: FileTimeToLocalFileTime(&time, &local);
4732: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
4733: }
4734: file_size = GetFileSize(hHandle, NULL);
4735: }
4736: *(UINT16 *)(sft + 0x0d) = dos_time;
4737: *(UINT16 *)(sft + 0x0f) = dos_date;
4738: *(UINT32 *)(sft + 0x11) = file_size;
4739: }
4740:
4741: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
4742: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
4743: my_strupr(fname);
4744: my_strupr(ext);
4745: memset(sft + 0x20, 0x20, 11);
4746: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
4747: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
4748:
4749: *(UINT16 *)(sft + 0x31) = psp_seg;
4750: }
1.1 root 4751: }
4752:
1.1.1.37 root 4753: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
4754: {
4755: msdos_file_handler_open(fd, path, atty, mode, info, psp_seg, 0, 0);
4756: }
4757:
1.1 root 4758: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
4759: {
4760: strcpy(file_handler[dst].path, file_handler[src].path);
4761: file_handler[dst].valid = 1;
4762: file_handler[dst].id = file_handler[src].id;
4763: file_handler[dst].atty = file_handler[src].atty;
4764: file_handler[dst].mode = file_handler[src].mode;
4765: file_handler[dst].info = file_handler[src].info;
4766: file_handler[dst].psp = psp_seg;
1.1.1.37 root 4767: file_handler[dst].sio_port = file_handler[src].sio_port;
4768: file_handler[dst].lpt_port = file_handler[src].lpt_port;
1.1 root 4769: }
4770:
1.1.1.20 root 4771: void msdos_file_handler_close(int fd)
1.1 root 4772: {
4773: file_handler[fd].valid = 0;
1.1.1.21 root 4774:
4775: if(fd < 20) {
4776: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
4777: }
1.1 root 4778: }
4779:
1.1.1.14 root 4780: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 4781: {
1.1.1.14 root 4782: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
4783: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
4784: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 4785: }
4786:
4787: // find file
4788:
4789: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
4790: {
4791: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4792: return(0); // search directory only !!!
4793: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
4794: return(0);
4795: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
4796: return(0);
4797: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4798: return(0);
4799: } else if((attribute & required_mask) != required_mask) {
4800: return(0);
4801: } else {
4802: return(1);
4803: }
4804: }
4805:
1.1.1.13 root 4806: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
4807: {
1.1.1.14 root 4808: if(fd->cAlternateFileName[0]) {
1.1.1.42 root 4809: return(1);
1.1.1.13 root 4810: }
4811: size_t len = strlen(fd->cFileName);
1.1.1.14 root 4812: if(len > 12) {
1.1.1.42 root 4813: return(0);
1.1.1.13 root 4814: }
4815: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 4816: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.42 root 4817: return(0);
1.1.1.13 root 4818: }
1.1.1.42 root 4819: return(1);
1.1.1.13 root 4820: }
4821:
1.1 root 4822: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
4823: {
4824: FILETIME local;
4825:
4826: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
4827: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
4828: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
4829:
4830: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
4831: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
4832: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
4833:
4834: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
4835: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
4836: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
4837: }
4838:
4839: // i/o
4840:
4841: void msdos_stdio_reopen()
4842: {
4843: if(!file_handler[0].valid) {
4844: _dup2(DUP_STDIN, 0);
4845: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
4846: }
4847: if(!file_handler[1].valid) {
4848: _dup2(DUP_STDOUT, 1);
4849: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
4850: }
4851: if(!file_handler[2].valid) {
4852: _dup2(DUP_STDERR, 2);
4853: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
4854: }
1.1.1.21 root 4855: if(!file_handler[3].valid) {
4856: _dup2(DUP_STDAUX, 3);
4857: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
4858: }
4859: if(!file_handler[4].valid) {
4860: _dup2(DUP_STDPRN, 4);
1.1.1.45 root 4861: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
4862: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1
1.1.1.21 root 4863: }
4864: for(int i = 0; i < 5; i++) {
4865: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
4866: msdos_psp_set_file_table(i, i, current_psp);
4867: }
4868: }
1.1 root 4869: }
4870:
1.1.1.37 root 4871: int msdos_read(int fd, void *buffer, unsigned int count)
4872: {
4873: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
4874: // read from serial port
4875: int read = 0;
4876: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
4877: UINT8 *buf = (UINT8 *)buffer;
4878: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
4879: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
1.1.1.38 root 4880: DWORD timeout = timeGetTime() + 1000;
4881: while(read < count) {
4882: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x01) {
4883: buf[read++] = sio_read(file_handler[fd].sio_port - 1, 0);
4884: timeout = timeGetTime() + 1000;
4885: } else {
4886: if(timeGetTime() > timeout) {
4887: break;
4888: }
4889: Sleep(10);
1.1.1.37 root 4890: }
4891: }
4892: sio_write(file_handler[fd].sio_port - 1, 3, selector);
4893: }
4894: return(read);
4895: }
4896: return(_read(fd, buffer, count));
4897: }
4898:
1.1 root 4899: int msdos_kbhit()
4900: {
4901: msdos_stdio_reopen();
4902:
1.1.1.20 root 4903: process_t *process = msdos_process_info_get(current_psp);
4904: int fd = msdos_psp_get_file_table(0, current_psp);
4905:
4906: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4907: // stdin is redirected to file
1.1.1.20 root 4908: return(eof(fd) == 0);
1.1 root 4909: }
4910:
4911: // check keyboard status
1.1.1.35 root 4912: if(key_recv != 0) {
1.1 root 4913: return(1);
4914: }
1.1.1.35 root 4915: if(key_buf_char != NULL && key_buf_scan != NULL) {
4916: #ifdef USE_SERVICE_THREAD
4917: EnterCriticalSection(&key_buf_crit_sect);
4918: #endif
4919: bool empty = key_buf_char->empty();
4920: #ifdef USE_SERVICE_THREAD
4921: LeaveCriticalSection(&key_buf_crit_sect);
4922: #endif
4923: if(!empty) return(1);
4924: }
4925: return(_kbhit());
1.1 root 4926: }
4927:
4928: int msdos_getch_ex(int echo)
4929: {
4930: static char prev = 0;
4931:
4932: msdos_stdio_reopen();
4933:
1.1.1.20 root 4934: process_t *process = msdos_process_info_get(current_psp);
4935: int fd = msdos_psp_get_file_table(0, current_psp);
4936:
4937: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4938: // stdin is redirected to file
4939: retry:
4940: char data;
1.1.1.37 root 4941: if(msdos_read(fd, &data, 1) == 1) {
1.1 root 4942: char tmp = data;
4943: if(data == 0x0a) {
4944: if(prev == 0x0d) {
4945: goto retry; // CRLF -> skip LF
4946: } else {
4947: data = 0x0d; // LF only -> CR
4948: }
4949: }
4950: prev = tmp;
4951: return(data);
4952: }
4953: return(EOF);
4954: }
4955:
4956: // input from console
1.1.1.5 root 4957: int key_char, key_scan;
1.1.1.33 root 4958: if(key_recv != 0) {
1.1.1.5 root 4959: key_char = (key_code >> 0) & 0xff;
4960: key_scan = (key_code >> 8) & 0xff;
4961: key_code >>= 16;
1.1.1.33 root 4962: key_recv >>= 16;
1.1.1.5 root 4963: } else {
1.1.1.35 root 4964: while(key_buf_char != NULL && key_buf_scan != NULL && !m_halted) {
4965: if(key_buf_char != NULL && key_buf_scan != NULL) {
4966: #ifdef USE_SERVICE_THREAD
4967: EnterCriticalSection(&key_buf_crit_sect);
4968: #endif
4969: bool empty = key_buf_char->empty();
4970: #ifdef USE_SERVICE_THREAD
4971: LeaveCriticalSection(&key_buf_crit_sect);
4972: #endif
4973: if(!empty) break;
4974: }
1.1.1.23 root 4975: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
4976: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
4977: if(_kbhit()) {
1.1.1.32 root 4978: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4979: #ifdef USE_SERVICE_THREAD
4980: EnterCriticalSection(&key_buf_crit_sect);
4981: #endif
1.1.1.32 root 4982: key_buf_char->write(_getch());
1.1.1.35 root 4983: key_buf_scan->write(0x00);
4984: #ifdef USE_SERVICE_THREAD
4985: LeaveCriticalSection(&key_buf_crit_sect);
4986: #endif
1.1.1.32 root 4987: }
1.1.1.23 root 4988: } else {
4989: Sleep(10);
4990: }
4991: } else {
4992: if(!update_key_buffer()) {
4993: Sleep(10);
4994: }
1.1.1.14 root 4995: }
4996: }
4997: if(m_halted) {
1.1.1.33 root 4998: // insert CR to terminate input loops
1.1.1.14 root 4999: key_char = 0x0d;
5000: key_scan = 0;
1.1.1.32 root 5001: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 5002: #ifdef USE_SERVICE_THREAD
5003: EnterCriticalSection(&key_buf_crit_sect);
5004: #endif
1.1.1.14 root 5005: key_char = key_buf_char->read();
5006: key_scan = key_buf_scan->read();
1.1.1.41 root 5007: // write to bottom of key buffer
5008: mem[0x43c] = (UINT8)key_char;
5009: mem[0x43d] = (UINT8)key_scan;
1.1.1.35 root 5010: #ifdef USE_SERVICE_THREAD
5011: LeaveCriticalSection(&key_buf_crit_sect);
5012: #endif
1.1.1.5 root 5013: }
1.1 root 5014: }
5015: if(echo && key_char) {
5016: msdos_putch(key_char);
5017: }
5018: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
5019: }
5020:
5021: inline int msdos_getch()
5022: {
5023: return(msdos_getch_ex(0));
5024: }
5025:
5026: inline int msdos_getche()
5027: {
5028: return(msdos_getch_ex(1));
5029: }
5030:
5031: int msdos_write(int fd, const void *buffer, unsigned int count)
5032: {
1.1.1.37 root 5033: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
5034: // write to serial port
1.1.1.38 root 5035: int written = 0;
1.1.1.37 root 5036: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
5037: UINT8 *buf = (UINT8 *)buffer;
5038: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
5039: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
1.1.1.38 root 5040: DWORD timeout = timeGetTime() + 1000;
5041: while(written < count) {
5042: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x20) {
5043: sio_write(file_handler[fd].sio_port - 1, 0, buf[written++]);
5044: timeout = timeGetTime() + 1000;
5045: } else {
5046: if(timeGetTime() > timeout) {
5047: break;
5048: }
5049: Sleep(10);
5050: }
1.1.1.37 root 5051: }
5052: sio_write(file_handler[fd].sio_port - 1, 3, selector);
5053: }
1.1.1.38 root 5054: return(written);
1.1.1.37 root 5055: } else if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].lpt_port >= 1 && file_handler[fd].lpt_port <= 3) {
5056: // write to printer port
5057: UINT8 *buf = (UINT8 *)buffer;
5058: for(unsigned int i = 0; i < count; i++) {
5059: // printer_out(file_handler[fd].lpt_port - 1, buf[i]);
5060: pcbios_printer_out(file_handler[fd].lpt_port - 1, buf[i]);
5061: }
5062: return(count);
5063: } else if(fd == 1 && file_handler[1].valid && !file_handler[1].atty) {
1.1 root 5064: // CR+LF -> LF
1.1.1.37 root 5065: static int is_cr = 0;
1.1 root 5066: UINT8 *buf = (UINT8 *)buffer;
5067: for(unsigned int i = 0; i < count; i++) {
5068: UINT8 data = buf[i];
5069: if(is_cr) {
5070: if(data != 0x0a) {
5071: UINT8 tmp = 0x0d;
5072: _write(1, &tmp, 1);
5073: }
5074: _write(1, &data, 1);
5075: is_cr = 0;
5076: } else if(data == 0x0d) {
5077: is_cr = 1;
5078: } else {
5079: _write(1, &data, 1);
5080: }
5081: }
5082: return(count);
5083: }
1.1.1.14 root 5084: vram_flush();
1.1 root 5085: return(_write(fd, buffer, count));
5086: }
5087:
5088: void msdos_putch(UINT8 data)
1.1.1.35 root 5089: #ifdef USE_SERVICE_THREAD
5090: {
5091: EnterCriticalSection(&putch_crit_sect);
5092: msdos_putch_tmp(data);
5093: LeaveCriticalSection(&putch_crit_sect);
5094: }
5095: void msdos_putch_tmp(UINT8 data)
5096: #endif
1.1 root 5097: {
1.1.1.34 root 5098: CONSOLE_SCREEN_BUFFER_INFO csbi;
5099: SMALL_RECT rect;
5100: COORD co;
1.1 root 5101: static int p = 0;
5102: static int is_kanji = 0;
5103: static int is_esc = 0;
5104: static int stored_x;
5105: static int stored_y;
5106: static WORD stored_a;
1.1.1.20 root 5107: static char tmp[64], out[64];
1.1 root 5108:
5109: msdos_stdio_reopen();
5110:
1.1.1.20 root 5111: process_t *process = msdos_process_info_get(current_psp);
5112: int fd = msdos_psp_get_file_table(1, current_psp);
5113:
5114: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 5115: // stdout is redirected to file
1.1.1.20 root 5116: msdos_write(fd, &data, 1);
1.1 root 5117: return;
5118: }
1.1.1.23 root 5119: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 5120:
5121: // output to console
5122: tmp[p++] = data;
5123:
1.1.1.14 root 5124: vram_flush();
5125:
1.1 root 5126: if(is_kanji) {
5127: // kanji character
5128: is_kanji = 0;
5129: } else if(is_esc) {
5130: // escape sequense
5131: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
5132: p = is_esc = 0;
5133: } else if(tmp[1] == '=' && p == 4) {
5134: co.X = tmp[3] - 0x20;
1.1.1.14 root 5135: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 5136: SetConsoleCursorPosition(hStdout, co);
5137: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5138: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 5139: cursor_moved = false;
5140: p = is_esc = 0;
5141: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
5142: GetConsoleScreenBufferInfo(hStdout, &csbi);
5143: co.X = csbi.dwCursorPosition.X;
5144: co.Y = csbi.dwCursorPosition.Y;
5145: WORD wAttributes = csbi.wAttributes;
5146:
5147: if(tmp[1] == 'D') {
5148: co.Y++;
5149: } else if(tmp[1] == 'E') {
5150: co.X = 0;
5151: co.Y++;
5152: } else if(tmp[1] == 'M') {
5153: co.Y--;
5154: } else if(tmp[1] == '*') {
1.1.1.14 root 5155: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5156: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5157: co.X = 0;
5158: co.Y = csbi.srWindow.Top;
1.1 root 5159: } else if(tmp[1] == '[') {
5160: int param[256], params = 0;
5161: memset(param, 0, sizeof(param));
5162: for(int i = 2; i < p; i++) {
5163: if(tmp[i] >= '0' && tmp[i] <= '9') {
5164: param[params] *= 10;
5165: param[params] += tmp[i] - '0';
5166: } else {
5167: params++;
5168: }
5169: }
5170: if(data == 'A') {
1.1.1.14 root 5171: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 5172: } else if(data == 'B') {
1.1.1.14 root 5173: co.Y += (params == 0) ? 1 : param[0];
1.1 root 5174: } else if(data == 'C') {
1.1.1.14 root 5175: co.X += (params == 0) ? 1 : param[0];
1.1 root 5176: } else if(data == 'D') {
1.1.1.14 root 5177: co.X -= (params == 0) ? 1 : param[0];
1.1 root 5178: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 5179: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
5180: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 5181: } else if(data == 'J') {
1.1.1.14 root 5182: clear_scr_buffer(csbi.wAttributes);
1.1 root 5183: if(param[0] == 0) {
5184: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5185: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5186: if(co.Y < csbi.srWindow.Bottom) {
5187: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5188: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5189: }
5190: } else if(param[0] == 1) {
1.1.1.14 root 5191: if(co.Y > csbi.srWindow.Top) {
5192: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
5193: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5194: }
5195: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5196: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5197: } else if(param[0] == 2) {
1.1.1.14 root 5198: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5199: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5200: co.X = co.Y = 0;
5201: }
5202: } else if(data == 'K') {
1.1.1.14 root 5203: clear_scr_buffer(csbi.wAttributes);
1.1 root 5204: if(param[0] == 0) {
5205: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5206: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5207: } else if(param[0] == 1) {
5208: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5209: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5210: } else if(param[0] == 2) {
5211: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5212: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5213: }
5214: } else if(data == 'L') {
1.1.1.14 root 5215: if(params == 0) {
5216: param[0] = 1;
1.1 root 5217: }
1.1.1.14 root 5218: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5219: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5220: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5221: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5222: clear_scr_buffer(csbi.wAttributes);
1.1 root 5223: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 5224: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5225: co.X = 0;
5226: } else if(data == 'M') {
1.1.1.14 root 5227: if(params == 0) {
5228: param[0] = 1;
5229: }
5230: if(co.Y + param[0] > csbi.srWindow.Bottom) {
5231: clear_scr_buffer(csbi.wAttributes);
5232: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5233: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5234: } else {
1.1.1.14 root 5235: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5236: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5237: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5238: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5239: clear_scr_buffer(csbi.wAttributes);
1.1 root 5240: }
5241: co.X = 0;
5242: } else if(data == 'h') {
5243: if(tmp[2] == '>' && tmp[3] == '5') {
5244: CONSOLE_CURSOR_INFO cur;
5245: GetConsoleCursorInfo(hStdout, &cur);
5246: if(cur.bVisible) {
5247: cur.bVisible = FALSE;
1.1.1.14 root 5248: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5249: }
5250: }
5251: } else if(data == 'l') {
5252: if(tmp[2] == '>' && tmp[3] == '5') {
5253: CONSOLE_CURSOR_INFO cur;
5254: GetConsoleCursorInfo(hStdout, &cur);
5255: if(!cur.bVisible) {
5256: cur.bVisible = TRUE;
1.1.1.14 root 5257: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5258: }
5259: }
5260: } else if(data == 'm') {
5261: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
5262: int reverse = 0, hidden = 0;
5263: for(int i = 0; i < params; i++) {
5264: if(param[i] == 1) {
5265: wAttributes |= FOREGROUND_INTENSITY;
5266: } else if(param[i] == 4) {
5267: wAttributes |= COMMON_LVB_UNDERSCORE;
5268: } else if(param[i] == 7) {
5269: reverse = 1;
5270: } else if(param[i] == 8 || param[i] == 16) {
5271: hidden = 1;
5272: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
5273: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
5274: if(param[i] >= 17 && param[i] <= 23) {
5275: param[i] -= 16;
5276: } else {
5277: param[i] -= 30;
5278: }
5279: if(param[i] & 1) {
5280: wAttributes |= FOREGROUND_RED;
5281: }
5282: if(param[i] & 2) {
5283: wAttributes |= FOREGROUND_GREEN;
5284: }
5285: if(param[i] & 4) {
5286: wAttributes |= FOREGROUND_BLUE;
5287: }
5288: } else if(param[i] >= 40 && param[i] <= 47) {
5289: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
5290: if((param[i] - 40) & 1) {
5291: wAttributes |= BACKGROUND_RED;
5292: }
5293: if((param[i] - 40) & 2) {
5294: wAttributes |= BACKGROUND_GREEN;
5295: }
5296: if((param[i] - 40) & 4) {
5297: wAttributes |= BACKGROUND_BLUE;
5298: }
5299: }
5300: }
5301: if(reverse) {
5302: wAttributes &= ~0xff;
5303: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
5304: }
5305: if(hidden) {
5306: wAttributes &= ~0x0f;
5307: wAttributes |= (wAttributes >> 4) & 0x0f;
5308: }
5309: } else if(data == 'n') {
5310: if(param[0] == 6) {
5311: char tmp[16];
5312: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
5313: int len = strlen(tmp);
1.1.1.32 root 5314: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 5315: #ifdef USE_SERVICE_THREAD
5316: EnterCriticalSection(&key_buf_crit_sect);
5317: #endif
1.1.1.32 root 5318: for(int i = 0; i < len; i++) {
5319: key_buf_char->write(tmp[i]);
5320: key_buf_scan->write(0x00);
5321: }
1.1.1.35 root 5322: #ifdef USE_SERVICE_THREAD
5323: LeaveCriticalSection(&key_buf_crit_sect);
5324: #endif
1.1 root 5325: }
5326: }
5327: } else if(data == 's') {
5328: stored_x = co.X;
5329: stored_y = co.Y;
5330: stored_a = wAttributes;
5331: } else if(data == 'u') {
5332: co.X = stored_x;
5333: co.Y = stored_y;
5334: wAttributes = stored_a;
5335: }
5336: }
5337: if(co.X < 0) {
5338: co.X = 0;
5339: } else if(co.X >= csbi.dwSize.X) {
5340: co.X = csbi.dwSize.X - 1;
5341: }
1.1.1.14 root 5342: if(co.Y < csbi.srWindow.Top) {
5343: co.Y = csbi.srWindow.Top;
5344: } else if(co.Y > csbi.srWindow.Bottom) {
5345: co.Y = csbi.srWindow.Bottom;
1.1 root 5346: }
5347: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
5348: SetConsoleCursorPosition(hStdout, co);
5349: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5350: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 5351: cursor_moved = false;
5352: }
5353: if(wAttributes != csbi.wAttributes) {
5354: SetConsoleTextAttribute(hStdout, wAttributes);
5355: }
5356: p = is_esc = 0;
5357: }
5358: return;
5359: } else {
5360: if(msdos_lead_byte_check(data)) {
5361: is_kanji = 1;
5362: return;
5363: } else if(data == 0x1b) {
5364: is_esc = 1;
5365: return;
5366: }
5367: }
1.1.1.20 root 5368:
5369: DWORD q = 0, num;
5370: is_kanji = 0;
5371: for(int i = 0; i < p; i++) {
5372: UINT8 c = tmp[i];
5373: if(is_kanji) {
5374: is_kanji = 0;
5375: } else if(msdos_lead_byte_check(data)) {
5376: is_kanji = 1;
5377: } else if(msdos_ctrl_code_check(data)) {
5378: out[q++] = '^';
5379: c += 'A' - 1;
5380: }
5381: out[q++] = c;
5382: }
1.1.1.34 root 5383: if(q == 1 && out[0] == 0x08) {
5384: // back space
5385: GetConsoleScreenBufferInfo(hStdout, &csbi);
5386: if(csbi.dwCursorPosition.X > 0) {
5387: co.X = csbi.dwCursorPosition.X - 1;
5388: co.Y = csbi.dwCursorPosition.Y;
5389: SetConsoleCursorPosition(hStdout, co);
5390: } else if(csbi.dwCursorPosition.Y > 0) {
5391: co.X = csbi.dwSize.X - 1;
5392: co.Y = csbi.dwCursorPosition.Y - 1;
5393: SetConsoleCursorPosition(hStdout, co);
5394: } else {
5395: WriteConsole(hStdout, out, q, &num, NULL); // to make sure
5396: }
5397: } else {
5398: WriteConsole(hStdout, out, q, &num, NULL);
5399: }
1.1 root 5400: p = 0;
1.1.1.14 root 5401:
1.1.1.15 root 5402: if(!restore_console_on_exit) {
5403: GetConsoleScreenBufferInfo(hStdout, &csbi);
5404: scr_top = csbi.srWindow.Top;
5405: }
1.1 root 5406: cursor_moved = true;
5407: }
5408:
5409: int msdos_aux_in()
5410: {
1.1.1.21 root 5411: msdos_stdio_reopen();
5412:
1.1.1.20 root 5413: process_t *process = msdos_process_info_get(current_psp);
5414: int fd = msdos_psp_get_file_table(3, current_psp);
5415:
5416: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 5417: char data = 0;
1.1.1.37 root 5418: msdos_read(fd, &data, 1);
1.1 root 5419: return(data);
5420: } else {
5421: return(EOF);
5422: }
5423: }
5424:
5425: void msdos_aux_out(char data)
5426: {
1.1.1.21 root 5427: msdos_stdio_reopen();
5428:
1.1.1.20 root 5429: process_t *process = msdos_process_info_get(current_psp);
5430: int fd = msdos_psp_get_file_table(3, current_psp);
5431:
5432: if(fd < process->max_files && file_handler[fd].valid) {
5433: msdos_write(fd, &data, 1);
1.1 root 5434: }
5435: }
5436:
5437: void msdos_prn_out(char data)
5438: {
1.1.1.21 root 5439: msdos_stdio_reopen();
5440:
1.1.1.20 root 5441: process_t *process = msdos_process_info_get(current_psp);
5442: int fd = msdos_psp_get_file_table(4, current_psp);
5443:
5444: if(fd < process->max_files && file_handler[fd].valid) {
5445: msdos_write(fd, &data, 1);
1.1 root 5446: }
5447: }
5448:
5449: // memory control
5450:
1.1.1.45 root 5451: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs, const char *prog_name)
1.1 root 5452: {
5453: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5454:
5455: mcb->mz = mz;
5456: mcb->psp = psp;
1.1.1.30 root 5457: mcb->paragraphs = paragraphs;
1.1.1.39 root 5458:
5459: if(prog_name != NULL) {
5460: memset(mcb->prog_name, 0, 8);
5461: memcpy(mcb->prog_name, prog_name, min(8, strlen(prog_name)));
5462: }
1.1 root 5463: return(mcb);
5464: }
5465:
1.1.1.39 root 5466: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
5467: {
5468: return(msdos_mcb_create(mcb_seg, mz, psp, paragraphs, NULL));
5469: }
5470:
1.1 root 5471: void msdos_mcb_check(mcb_t *mcb)
5472: {
5473: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 5474: #if 0
5475: // shutdown now !!!
5476: fatalerror("broken memory control block\n");
5477: #else
5478: // return error code and continue
5479: throw(0x07); // broken memory control block
5480: #endif
1.1 root 5481: }
5482: }
5483:
1.1.1.39 root 5484: void msdos_mem_split(int seg, int paragraphs)
1.1 root 5485: {
5486: int mcb_seg = seg - 1;
5487: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5488: msdos_mcb_check(mcb);
5489:
1.1.1.30 root 5490: if(mcb->paragraphs > paragraphs) {
1.1 root 5491: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 5492: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 5493:
5494: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5495: mcb->mz = 'M';
1.1.1.30 root 5496: mcb->paragraphs = paragraphs;
1.1 root 5497: }
5498: }
5499:
5500: void msdos_mem_merge(int seg)
5501: {
5502: int mcb_seg = seg - 1;
5503: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5504: msdos_mcb_check(mcb);
5505:
5506: while(1) {
5507: if(mcb->mz == 'Z') {
5508: break;
5509: }
1.1.1.30 root 5510: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 5511: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5512: msdos_mcb_check(next_mcb);
5513:
5514: if(next_mcb->psp != 0) {
5515: break;
5516: }
5517: mcb->mz = next_mcb->mz;
1.1.1.30 root 5518: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 5519: }
5520: }
5521:
1.1.1.8 root 5522: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 5523: {
5524: while(1) {
5525: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5526: bool last_block;
1.1 root 5527:
1.1.1.14 root 5528: if(mcb->psp == 0) {
5529: msdos_mem_merge(mcb_seg + 1);
5530: } else {
5531: msdos_mcb_check(mcb);
5532: }
1.1.1.33 root 5533: if(!(last_block = (mcb->mz == 'Z'))) {
5534: // check if the next is dummy mcb to link to umb
5535: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5536: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5537: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5538: }
5539: if(!(new_process && !last_block)) {
1.1.1.30 root 5540: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 5541: msdos_mem_split(mcb_seg + 1, paragraphs);
5542: mcb->psp = current_psp;
5543: return(mcb_seg + 1);
5544: }
5545: }
5546: if(mcb->mz == 'Z') {
5547: break;
5548: }
1.1.1.30 root 5549: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5550: }
5551: return(-1);
5552: }
5553:
5554: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5555: {
5556: int mcb_seg = seg - 1;
5557: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5558: msdos_mcb_check(mcb);
1.1.1.30 root 5559: int current_paragraphs = mcb->paragraphs;
1.1 root 5560:
5561: msdos_mem_merge(seg);
1.1.1.30 root 5562: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 5563: if(max_paragraphs) {
1.1.1.30 root 5564: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 5565: }
1.1 root 5566: msdos_mem_split(seg, current_paragraphs);
5567: return(-1);
5568: }
5569: msdos_mem_split(seg, paragraphs);
5570: return(0);
5571: }
5572:
5573: void msdos_mem_free(int seg)
5574: {
5575: int mcb_seg = seg - 1;
5576: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5577: msdos_mcb_check(mcb);
5578:
5579: mcb->psp = 0;
5580: msdos_mem_merge(seg);
5581: }
5582:
1.1.1.8 root 5583: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 5584: {
5585: int max_paragraphs = 0;
5586:
5587: while(1) {
5588: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5589: bool last_block;
5590:
1.1 root 5591: msdos_mcb_check(mcb);
5592:
1.1.1.33 root 5593: if(!(last_block = (mcb->mz == 'Z'))) {
5594: // check if the next is dummy mcb to link to umb
5595: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5596: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5597: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5598: }
5599: if(!(new_process && !last_block)) {
1.1.1.30 root 5600: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
5601: max_paragraphs = mcb->paragraphs;
1.1 root 5602: }
5603: }
5604: if(mcb->mz == 'Z') {
5605: break;
5606: }
1.1.1.30 root 5607: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5608: }
1.1.1.14 root 5609: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 5610: }
5611:
1.1.1.8 root 5612: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
5613: {
5614: int last_seg = -1;
5615:
5616: while(1) {
5617: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5618: msdos_mcb_check(mcb);
5619:
1.1.1.14 root 5620: if(mcb->psp == psp) {
1.1.1.8 root 5621: last_seg = mcb_seg;
5622: }
1.1.1.14 root 5623: if(mcb->mz == 'Z') {
5624: break;
5625: }
1.1.1.30 root 5626: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 5627: }
5628: return(last_seg);
5629: }
5630:
1.1.1.19 root 5631: int msdos_mem_get_umb_linked()
5632: {
1.1.1.33 root 5633: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5634: msdos_mcb_check(mcb);
1.1.1.19 root 5635:
1.1.1.33 root 5636: if(mcb->mz == 'M') {
5637: return(-1);
1.1.1.19 root 5638: }
5639: return(0);
5640: }
5641:
1.1.1.33 root 5642: void msdos_mem_link_umb()
1.1.1.19 root 5643: {
1.1.1.33 root 5644: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5645: msdos_mcb_check(mcb);
1.1.1.19 root 5646:
1.1.1.33 root 5647: mcb->mz = 'M';
5648: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
1.1.1.39 root 5649:
5650: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 5651: }
5652:
1.1.1.33 root 5653: void msdos_mem_unlink_umb()
1.1.1.19 root 5654: {
1.1.1.33 root 5655: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5656: msdos_mcb_check(mcb);
1.1.1.19 root 5657:
1.1.1.33 root 5658: mcb->mz = 'Z';
5659: mcb->paragraphs = 0;
1.1.1.39 root 5660:
5661: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 5662: }
5663:
1.1.1.29 root 5664: #ifdef SUPPORT_HMA
5665:
5666: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
5667: {
5668: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5669:
5670: mcb->ms[0] = 'M';
5671: mcb->ms[1] = 'S';
5672: mcb->owner = owner;
5673: mcb->size = size;
5674: mcb->next = next;
5675: return(mcb);
5676: }
5677:
5678: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
5679: {
5680: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
5681: }
5682:
5683: int msdos_hma_mem_split(int offset, int size)
5684: {
5685: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5686:
5687: if(!msdos_is_hma_mcb_valid(mcb)) {
5688: return(-1);
5689: }
5690: if(mcb->size >= size + 0x10) {
5691: int new_offset = offset + 0x10 + size;
5692: int new_size = mcb->size - 0x10 - size;
5693:
5694: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
5695: mcb->size = size;
5696: mcb->next = new_offset;
5697: return(0);
5698: }
5699: return(-1);
5700: }
5701:
5702: void msdos_hma_mem_merge(int offset)
5703: {
5704: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5705:
5706: if(!msdos_is_hma_mcb_valid(mcb)) {
5707: return;
5708: }
5709: while(1) {
5710: if(mcb->next == 0) {
5711: break;
5712: }
5713: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
5714:
5715: if(!msdos_is_hma_mcb_valid(next_mcb)) {
5716: return;
5717: }
5718: if(next_mcb->owner != 0) {
5719: break;
5720: }
5721: mcb->size += 0x10 + next_mcb->size;
5722: mcb->next = next_mcb->next;
5723: }
5724: }
5725:
5726: int msdos_hma_mem_alloc(int size, UINT16 owner)
5727: {
5728: int offset = 0x10; // first mcb in HMA
5729:
5730: while(1) {
5731: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5732:
5733: if(!msdos_is_hma_mcb_valid(mcb)) {
5734: return(-1);
5735: }
5736: if(mcb->owner == 0) {
5737: msdos_hma_mem_merge(offset);
5738: }
5739: if(mcb->owner == 0 && mcb->size >= size) {
5740: msdos_hma_mem_split(offset, size);
5741: mcb->owner = owner;
5742: return(offset);
5743: }
5744: if(mcb->next == 0) {
5745: break;
5746: }
5747: offset = mcb->next;
5748: }
5749: return(-1);
5750: }
5751:
5752: int msdos_hma_mem_realloc(int offset, int size)
5753: {
5754: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5755:
5756: if(!msdos_is_hma_mcb_valid(mcb)) {
5757: return(-1);
5758: }
5759: if(mcb->size < size) {
5760: return(-1);
5761: }
5762: msdos_hma_mem_split(offset, size);
5763: return(0);
5764: }
5765:
5766: void msdos_hma_mem_free(int offset)
5767: {
5768: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5769:
5770: if(!msdos_is_hma_mcb_valid(mcb)) {
5771: return;
5772: }
5773: mcb->owner = 0;
5774: msdos_hma_mem_merge(offset);
5775: }
5776:
5777: int msdos_hma_mem_get_free(int *available_offset)
5778: {
5779: int offset = 0x10; // first mcb in HMA
5780: int size = 0;
5781:
5782: while(1) {
5783: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5784:
5785: if(!msdos_is_hma_mcb_valid(mcb)) {
5786: return(0);
5787: }
5788: if(mcb->owner == 0 && size < mcb->size) {
5789: if(available_offset != NULL) {
5790: *available_offset = offset;
5791: }
5792: size = mcb->size;
5793: }
5794: if(mcb->next == 0) {
5795: break;
5796: }
5797: offset = mcb->next;
5798: }
5799: return(size);
5800: }
5801:
5802: #endif
5803:
1.1 root 5804: // environment
5805:
1.1.1.45 root 5806: void msdos_env_set_argv(int env_seg, const char *argv)
1.1 root 5807: {
5808: char *dst = (char *)(mem + (env_seg << 4));
5809:
5810: while(1) {
5811: if(dst[0] == 0) {
5812: break;
5813: }
5814: dst += strlen(dst) + 1;
5815: }
5816: *dst++ = 0; // end of environment
5817: *dst++ = 1; // top of argv[0]
5818: *dst++ = 0;
5819: memcpy(dst, argv, strlen(argv));
5820: dst += strlen(argv);
5821: *dst++ = 0;
5822: *dst++ = 0;
5823: }
5824:
1.1.1.45 root 5825: const char *msdos_env_get_argv(int env_seg)
1.1 root 5826: {
5827: static char env[ENV_SIZE];
5828: char *src = env;
5829:
5830: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5831: while(1) {
5832: if(src[0] == 0) {
5833: if(src[1] == 1) {
5834: return(src + 3);
5835: }
5836: break;
5837: }
5838: src += strlen(src) + 1;
5839: }
5840: return(NULL);
5841: }
5842:
1.1.1.45 root 5843: const char *msdos_env_get(int env_seg, const char *name)
1.1 root 5844: {
5845: static char env[ENV_SIZE];
5846: char *src = env;
5847:
5848: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5849: while(1) {
5850: if(src[0] == 0) {
5851: break;
5852: }
5853: int len = strlen(src);
5854: char *n = my_strtok(src, "=");
5855: char *v = src + strlen(n) + 1;
5856:
5857: if(_stricmp(name, n) == 0) {
5858: return(v);
5859: }
5860: src += len + 1;
5861: }
5862: return(NULL);
5863: }
5864:
1.1.1.45 root 5865: void msdos_env_set(int env_seg, const char *name, const char *value)
1.1 root 5866: {
5867: char env[ENV_SIZE];
5868: char *src = env;
5869: char *dst = (char *)(mem + (env_seg << 4));
1.1.1.45 root 5870: const char *argv = msdos_env_get_argv(env_seg);
1.1 root 5871: int done = 0;
5872:
5873: memcpy(src, dst, ENV_SIZE);
5874: memset(dst, 0, ENV_SIZE);
5875: while(1) {
5876: if(src[0] == 0) {
5877: break;
5878: }
5879: int len = strlen(src);
5880: char *n = my_strtok(src, "=");
5881: char *v = src + strlen(n) + 1;
5882: char tmp[1024];
5883:
5884: if(_stricmp(name, n) == 0) {
5885: sprintf(tmp, "%s=%s", n, value);
5886: done = 1;
5887: } else {
5888: sprintf(tmp, "%s=%s", n, v);
5889: }
5890: memcpy(dst, tmp, strlen(tmp));
5891: dst += strlen(tmp) + 1;
5892: src += len + 1;
5893: }
5894: if(!done) {
5895: char tmp[1024];
5896:
5897: sprintf(tmp, "%s=%s", name, value);
5898: memcpy(dst, tmp, strlen(tmp));
5899: dst += strlen(tmp) + 1;
5900: }
5901: if(argv) {
5902: *dst++ = 0; // end of environment
5903: *dst++ = 1; // top of argv[0]
5904: *dst++ = 0;
5905: memcpy(dst, argv, strlen(argv));
5906: dst += strlen(argv);
5907: *dst++ = 0;
5908: *dst++ = 0;
5909: }
5910: }
5911:
5912: // process
5913:
1.1.1.8 root 5914: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 5915: {
5916: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5917:
5918: memset(psp, 0, PSP_SIZE);
5919: psp->exit[0] = 0xcd;
5920: psp->exit[1] = 0x20;
1.1.1.8 root 5921: psp->first_mcb = mcb_seg;
1.1.1.46 root 5922: #if 1
1.1.1.49! root 5923: psp->call5[0] = 0xcd; // int 30h
! 5924: psp->call5[1] = 0x30;
1.1.1.46 root 5925: psp->call5[2] = 0xc3; // ret
5926: #else
5927: psp->call5[0] = 0x8a; // mov ah, cl
5928: psp->call5[1] = 0xe1;
5929: psp->call5[2] = 0xcd; // int 21h
5930: psp->call5[3] = 0x21;
5931: psp->call5[4] = 0xc3; // ret
5932: #endif
1.1 root 5933: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5934: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5935: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5936: psp->parent_psp = parent_psp;
1.1.1.20 root 5937: if(parent_psp == (UINT16)-1) {
5938: for(int i = 0; i < 20; i++) {
5939: if(file_handler[i].valid) {
5940: psp->file_table[i] = i;
5941: } else {
5942: psp->file_table[i] = 0xff;
5943: }
1.1 root 5944: }
1.1.1.20 root 5945: } else {
5946: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 5947: }
5948: psp->env_seg = env_seg;
5949: psp->stack.w.l = REG16(SP);
1.1.1.3 root 5950: psp->stack.w.h = SREG(SS);
1.1.1.14 root 5951: psp->file_table_size = 20;
5952: psp->file_table_ptr.w.l = 0x18;
5953: psp->file_table_ptr.w.h = psp_seg;
1.1 root 5954: psp->service[0] = 0xcd;
5955: psp->service[1] = 0x21;
5956: psp->service[2] = 0xcb;
5957: return(psp);
5958: }
5959:
1.1.1.20 root 5960: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
5961: {
5962: if(psp_seg && fd < 20) {
5963: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5964: psp->file_table[fd] = value;
5965: }
5966: }
5967:
5968: int msdos_psp_get_file_table(int fd, int psp_seg)
5969: {
5970: if(psp_seg && fd < 20) {
5971: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5972: fd = psp->file_table[fd];
5973: }
5974: return fd;
5975: }
5976:
1.1.1.45 root 5977: int msdos_process_exec(const char *cmd, param_block_t *param, UINT8 al)
1.1 root 5978: {
5979: // load command file
5980: int fd = -1;
1.1.1.45 root 5981: int sio_port = 0;
5982: int lpt_port = 0;
1.1 root 5983: int dos_command = 0;
1.1.1.24 root 5984: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1.1.38 root 5985: char pipe_stdin_path[MAX_PATH] = {0};
5986: char pipe_stdout_path[MAX_PATH] = {0};
1.1.1.39 root 5987: char pipe_stderr_path[MAX_PATH] = {0};
1.1 root 5988:
5989: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5990: int opt_len = mem[opt_ofs];
5991: memset(opt, 0, sizeof(opt));
5992: memcpy(opt, mem + opt_ofs + 1, opt_len);
5993:
1.1.1.14 root 5994: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
5995: // this is a batch file, run command.com
5996: char tmp[MAX_PATH];
5997: if(opt_len != 0) {
5998: sprintf(tmp, "/C %s %s", cmd, opt);
5999: } else {
6000: sprintf(tmp, "/C %s", cmd);
6001: }
6002: strcpy(opt, tmp);
6003: opt_len = strlen(opt);
6004: mem[opt_ofs] = opt_len;
6005: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6006: strcpy(command, comspec_path);
6007: strcpy(name_tmp, "COMMAND.COM");
6008: } else {
6009: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
6010: // redirect C:\COMMAND.COM to comspec_path
6011: strcpy(command, comspec_path);
6012: } else {
6013: strcpy(command, cmd);
6014: }
1.1.1.24 root 6015: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
6016: return(-1);
6017: }
1.1.1.14 root 6018: memset(name_tmp, 0, sizeof(name_tmp));
6019: strcpy(name_tmp, name);
6020:
6021: // check command.com
1.1.1.38 root 6022: if((_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) && _access(comspec_path, 0) != 0) {
6023: // we can not load command.com, so run program directly if "command /c (program)" is specified
1.1.1.14 root 6024: if(opt_len == 0) {
6025: // process_t *current_process = msdos_process_info_get(current_psp);
6026: process_t *current_process = NULL;
6027: for(int i = 0; i < MAX_PROCESS; i++) {
6028: if(process[i].psp == current_psp) {
6029: current_process = &process[i];
6030: break;
6031: }
6032: }
6033: if(current_process != NULL) {
6034: param->cmd_line.dw = current_process->dta.dw;
6035: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
6036: opt_len = mem[opt_ofs];
6037: memset(opt, 0, sizeof(opt));
6038: memcpy(opt, mem + opt_ofs + 1, opt_len);
6039: }
6040: }
6041: for(int i = 0; i < opt_len; i++) {
6042: if(opt[i] == ' ') {
6043: continue;
6044: }
6045: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
6046: for(int j = i + 3; j < opt_len; j++) {
6047: if(opt[j] == ' ') {
6048: continue;
6049: }
6050: char *token = my_strtok(opt + j, " ");
6051:
1.1.1.38 root 6052: strcpy(command, token);
6053: char tmp[MAX_PATH];
6054: strcpy(tmp, token + strlen(token) + 1);
1.1.1.39 root 6055: strcpy(opt, "");
6056: for(int i = 0; i < strlen(tmp); i++) {
6057: if(tmp[i] != ' ') {
6058: strcpy(opt, tmp + i);
6059: break;
6060: }
6061: }
6062: strcpy(tmp, opt);
1.1.1.38 root 6063:
6064: if(al == 0x00) {
1.1.1.39 root 6065: #define GET_FILE_PATH() { \
6066: if(token[0] != '>' && token[0] != '<') { \
6067: token++; \
6068: } \
6069: token++; \
6070: while(*token == ' ') { \
6071: token++; \
6072: } \
6073: char *ptr = token; \
6074: while(*ptr != ' ' && *ptr != '\r' && *ptr != '\0') { \
6075: ptr++; \
6076: } \
6077: *ptr = '\0'; \
6078: }
6079: if((token = strstr(opt, "0<")) != NULL || (token = strstr(opt, "<")) != NULL) {
6080: GET_FILE_PATH();
1.1.1.38 root 6081: strcpy(pipe_stdin_path, token);
6082: strcpy(opt, tmp);
6083: }
1.1.1.39 root 6084: if((token = strstr(opt, "1>")) != NULL || (token = strstr(opt, ">")) != NULL) {
6085: GET_FILE_PATH();
1.1.1.38 root 6086: strcpy(pipe_stdout_path, token);
6087: strcpy(opt, tmp);
6088: }
1.1.1.39 root 6089: if((token = strstr(opt, "2>")) != NULL) {
6090: GET_FILE_PATH();
6091: strcpy(pipe_stderr_path, token);
6092: strcpy(opt, tmp);
6093: }
6094: #undef GET_FILE_PATH
6095:
6096: if((token = strstr(opt, "0<")) != NULL) {
6097: *token = '\0';
6098: }
6099: if((token = strstr(opt, "1>")) != NULL) {
6100: *token = '\0';
6101: }
6102: if((token = strstr(opt, "2>")) != NULL) {
6103: *token = '\0';
6104: }
1.1.1.38 root 6105: if((token = strstr(opt, "<")) != NULL) {
6106: *token = '\0';
6107: }
6108: if((token = strstr(opt, ">")) != NULL) {
6109: *token = '\0';
6110: }
1.1.1.14 root 6111: }
1.1.1.39 root 6112: for(int i = strlen(opt) - 1; i >= 0 && opt[i] == ' '; i--) {
6113: opt[i] = '\0';
6114: }
1.1.1.38 root 6115: opt_len = strlen(opt);
6116: mem[opt_ofs] = opt_len;
6117: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6118: dos_command = 1;
1.1.1.14 root 6119: break;
1.1 root 6120: }
6121: }
1.1.1.14 root 6122: break;
1.1 root 6123: }
6124: }
6125: }
6126:
6127: // load command file
6128: strcpy(path, command);
6129: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
6130: sprintf(path, "%s.COM", command);
6131: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
6132: sprintf(path, "%s.EXE", command);
6133: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 6134: sprintf(path, "%s.BAT", command);
6135: if(_access(path, 0) == 0) {
6136: // this is a batch file, run command.com
6137: char tmp[MAX_PATH];
6138: if(opt_len != 0) {
6139: sprintf(tmp, "/C %s %s", path, opt);
6140: } else {
6141: sprintf(tmp, "/C %s", path);
6142: }
6143: strcpy(opt, tmp);
6144: opt_len = strlen(opt);
6145: mem[opt_ofs] = opt_len;
6146: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6147: strcpy(path, comspec_path);
6148: strcpy(name_tmp, "COMMAND.COM");
6149: fd = _open(path, _O_RDONLY | _O_BINARY);
6150: } else {
6151: // search path in parent environments
6152: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
1.1.1.45 root 6153: const char *env = msdos_env_get(parent_psp->env_seg, "PATH");
1.1.1.14 root 6154: if(env != NULL) {
6155: char env_path[4096];
6156: strcpy(env_path, env);
6157: char *token = my_strtok(env_path, ";");
6158:
6159: while(token != NULL) {
6160: if(strlen(token) != 0) {
6161: sprintf(path, "%s", msdos_combine_path(token, command));
6162: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6163: break;
6164: }
6165: sprintf(path, "%s.COM", msdos_combine_path(token, command));
6166: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6167: break;
6168: }
6169: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
6170: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6171: break;
6172: }
6173: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
6174: if(_access(path, 0) == 0) {
6175: // this is a batch file, run command.com
6176: char tmp[MAX_PATH];
6177: if(opt_len != 0) {
6178: sprintf(tmp, "/C %s %s", path, opt);
6179: } else {
6180: sprintf(tmp, "/C %s", path);
6181: }
6182: strcpy(opt, tmp);
6183: opt_len = strlen(opt);
6184: mem[opt_ofs] = opt_len;
6185: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6186: strcpy(path, comspec_path);
6187: strcpy(name_tmp, "COMMAND.COM");
6188: fd = _open(path, _O_RDONLY | _O_BINARY);
6189: break;
6190: }
1.1.1.8 root 6191: }
1.1.1.14 root 6192: token = my_strtok(NULL, ";");
1.1 root 6193: }
6194: }
6195: }
6196: }
6197: }
6198: }
6199: if(fd == -1) {
1.1.1.38 root 6200: // we can not find command.com in the path, so open comspec_path
6201: if(_stricmp(command, "COMMAND.COM") == 0 || _stricmp(command, "COMMAND") == 0) {
6202: strcpy(command, comspec_path);
6203: strcpy(path, command);
6204: fd = _open(path, _O_RDONLY | _O_BINARY);
6205: }
6206: }
6207: if(fd == -1) {
1.1 root 6208: if(dos_command) {
6209: // may be dos command
6210: char tmp[MAX_PATH];
6211: sprintf(tmp, "%s %s", command, opt);
6212: system(tmp);
6213: return(0);
6214: } else {
6215: return(-1);
6216: }
6217: }
6218: _read(fd, file_buffer, sizeof(file_buffer));
6219: _close(fd);
6220:
6221: // copy environment
1.1.1.29 root 6222: int umb_linked, env_seg, psp_seg;
1.1 root 6223:
1.1.1.29 root 6224: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6225: msdos_mem_unlink_umb();
6226: }
1.1.1.8 root 6227: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 6228: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
6229: if(umb_linked != 0) {
6230: msdos_mem_link_umb();
6231: }
6232: return(-1);
6233: }
1.1 root 6234: }
6235: if(param->env_seg == 0) {
6236: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
6237: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
6238: } else {
6239: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
6240: }
6241: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
6242:
6243: // check exe header
6244: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 6245: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 6246: UINT16 cs, ss, ip, sp;
6247:
6248: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6249: // memory allocation
6250: int header_size = header->header_size * 16;
6251: int load_size = header->pages * 512 - header_size;
6252: if(header_size + load_size < 512) {
6253: load_size = 512 - header_size;
6254: }
6255: paragraphs = (PSP_SIZE + load_size) >> 4;
6256: if(paragraphs + header->min_alloc > free_paragraphs) {
6257: msdos_mem_free(env_seg);
6258: return(-1);
6259: }
6260: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
6261: if(paragraphs > free_paragraphs) {
6262: paragraphs = free_paragraphs;
6263: }
1.1.1.8 root 6264: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6265: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6266: if(umb_linked != 0) {
6267: msdos_mem_link_umb();
6268: }
6269: msdos_mem_free(env_seg);
6270: return(-1);
6271: }
1.1 root 6272: }
6273: // relocation
6274: int start_seg = psp_seg + (PSP_SIZE >> 4);
6275: for(int i = 0; i < header->relocations; i++) {
6276: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6277: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6278: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6279: }
6280: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
6281: // segments
6282: cs = header->init_cs + start_seg;
6283: ss = header->init_ss + start_seg;
6284: ip = header->init_ip;
6285: sp = header->init_sp - 2; // for symdeb
6286: } else {
6287: // memory allocation
6288: paragraphs = free_paragraphs;
1.1.1.8 root 6289: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6290: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6291: if(umb_linked != 0) {
6292: msdos_mem_link_umb();
6293: }
6294: msdos_mem_free(env_seg);
6295: return(-1);
6296: }
1.1 root 6297: }
6298: int start_seg = psp_seg + (PSP_SIZE >> 4);
6299: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
6300: // segments
6301: cs = ss = psp_seg;
6302: ip = 0x100;
6303: sp = 0xfffe;
6304: }
1.1.1.29 root 6305: if(umb_linked != 0) {
6306: msdos_mem_link_umb();
6307: }
1.1 root 6308:
6309: // create psp
1.1.1.3 root 6310: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
6311: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 6312: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
6313: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
6314: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
6315: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
6316:
6317: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
6318: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
6319: mcb_psp->psp = mcb_env->psp = psp_seg;
6320:
1.1.1.4 root 6321: for(int i = 0; i < 8; i++) {
6322: if(name_tmp[i] == '.') {
6323: mcb_psp->prog_name[i] = '\0';
6324: break;
6325: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
6326: mcb_psp->prog_name[i] = name_tmp[i];
6327: i++;
6328: mcb_psp->prog_name[i] = name_tmp[i];
6329: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
6330: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
6331: } else {
6332: mcb_psp->prog_name[i] = name_tmp[i];
6333: }
6334: }
6335:
1.1 root 6336: // process info
6337: process_t *process = msdos_process_info_create(psp_seg);
6338: strcpy(process->module_dir, msdos_short_full_dir(path));
1.1.1.33 root 6339: #ifdef USE_DEBUGGER
6340: strcpy(process->module_path, path);
6341: #endif
1.1 root 6342: process->dta.w.l = 0x80;
6343: process->dta.w.h = psp_seg;
6344: process->switchar = '/';
6345: process->max_files = 20;
6346: process->parent_int_10h_feh_called = int_10h_feh_called;
6347: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 6348: process->parent_ds = SREG(DS);
1.1.1.31 root 6349: process->parent_es = SREG(ES);
1.1 root 6350:
6351: current_psp = psp_seg;
1.1.1.23 root 6352: msdos_sda_update(current_psp);
1.1 root 6353:
6354: if(al == 0x00) {
6355: int_10h_feh_called = int_10h_ffh_called = false;
6356:
1.1.1.38 root 6357: // pipe
6358: if(pipe_stdin_path[0] != '\0') {
1.1.1.45 root 6359: // if((fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY)) != -1) {
6360: if(msdos_is_device_path(pipe_stdin_path)) {
6361: fd = msdos_open_device(pipe_stdin_path, _O_RDONLY | _O_BINARY, &sio_port, &lpt_port);
6362: } else {
6363: fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY);
6364: }
6365: if(fd != -1) {
6366: msdos_file_handler_open(fd, pipe_stdin_path, _isatty(fd), 0, msdos_device_info(pipe_stdin_path), current_psp, sio_port, lpt_port);
1.1.1.38 root 6367: psp->file_table[0] = fd;
6368: msdos_psp_set_file_table(fd, fd, current_psp);
6369: }
6370: }
6371: if(pipe_stdout_path[0] != '\0') {
6372: if(_access(pipe_stdout_path, 0) == 0) {
6373: SetFileAttributes(pipe_stdout_path, FILE_ATTRIBUTE_NORMAL);
6374: DeleteFile(pipe_stdout_path);
6375: }
1.1.1.45 root 6376: // if((fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) {
6377: if(msdos_is_device_path(pipe_stdout_path)) {
6378: fd = msdos_open_device(pipe_stdout_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
6379: } else {
6380: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6381: }
6382: if(fd != -1) {
6383: msdos_file_handler_open(fd, pipe_stdout_path, _isatty(fd), 1, msdos_device_info(pipe_stdout_path), current_psp, sio_port, lpt_port);
1.1.1.38 root 6384: psp->file_table[1] = fd;
6385: msdos_psp_set_file_table(fd, fd, current_psp);
6386: }
6387: }
1.1.1.39 root 6388: if(pipe_stderr_path[0] != '\0') {
6389: if(_access(pipe_stderr_path, 0) == 0) {
6390: SetFileAttributes(pipe_stderr_path, FILE_ATTRIBUTE_NORMAL);
6391: DeleteFile(pipe_stderr_path);
6392: }
1.1.1.45 root 6393: // if((fd = _open(pipe_stderr_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) {
6394: if(msdos_is_device_path(pipe_stderr_path)) {
6395: fd = msdos_open_device(pipe_stderr_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
6396: } else {
6397: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6398: }
6399: if(fd != -1) {
6400: msdos_file_handler_open(fd, pipe_stderr_path, _isatty(fd), 1, msdos_device_info(pipe_stderr_path), current_psp, sio_port, lpt_port);
1.1.1.39 root 6401: psp->file_table[2] = fd;
6402: msdos_psp_set_file_table(fd, fd, current_psp);
6403: }
6404: }
1.1.1.38 root 6405:
1.1 root 6406: // registers and segments
6407: REG16(AX) = REG16(BX) = 0x00;
6408: REG16(CX) = 0xff;
6409: REG16(DX) = psp_seg;
6410: REG16(SI) = ip;
6411: REG16(DI) = sp;
6412: REG16(SP) = sp;
1.1.1.3 root 6413: SREG(DS) = SREG(ES) = psp_seg;
6414: SREG(SS) = ss;
6415: i386_load_segment_descriptor(DS);
6416: i386_load_segment_descriptor(ES);
6417: i386_load_segment_descriptor(SS);
1.1 root 6418:
6419: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
6420: i386_jmp_far(cs, ip);
6421: } else if(al == 0x01) {
6422: // copy ss:sp and cs:ip to param block
6423: param->sp = sp;
6424: param->ss = ss;
6425: param->ip = ip;
6426: param->cs = cs;
1.1.1.31 root 6427:
6428: // the AX value to be passed to the child program is put on top of the child's stack
6429: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 6430: }
6431: return(0);
6432: }
6433:
6434: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
6435: {
6436: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6437:
6438: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
6439: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
6440: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
6441:
1.1.1.3 root 6442: SREG(SS) = psp->stack.w.h;
6443: i386_load_segment_descriptor(SS);
1.1 root 6444: REG16(SP) = psp->stack.w.l;
6445: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
6446:
1.1.1.28 root 6447: // process_t *current_process = msdos_process_info_get(psp_seg);
6448: process_t *current_process = NULL;
6449: for(int i = 0; i < MAX_PROCESS; i++) {
6450: if(process[i].psp == psp_seg) {
6451: current_process = &process[i];
6452: break;
6453: }
6454: }
6455: if(current_process == NULL) {
6456: throw(0x1f); // general failure
6457: }
6458: int_10h_feh_called = current_process->parent_int_10h_feh_called;
6459: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
6460: if(current_process->called_by_int2eh) {
6461: REG16(AX) = ret;
6462: }
6463: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 6464: SREG(ES) = current_process->parent_es;
1.1.1.14 root 6465: i386_load_segment_descriptor(DS);
1.1.1.31 root 6466: i386_load_segment_descriptor(ES);
1.1 root 6467:
6468: if(mem_free) {
1.1.1.8 root 6469: int mcb_seg;
6470: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
6471: msdos_mem_free(mcb_seg + 1);
6472: }
6473: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
6474: msdos_mem_free(mcb_seg + 1);
6475: }
1.1 root 6476:
6477: for(int i = 0; i < MAX_FILES; i++) {
6478: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
6479: _close(i);
1.1.1.20 root 6480: msdos_file_handler_close(i);
6481: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 6482: }
6483: }
1.1.1.13 root 6484: msdos_dta_info_free(psp_seg);
1.1 root 6485: }
1.1.1.14 root 6486: msdos_stdio_reopen();
1.1 root 6487:
1.1.1.28 root 6488: memset(current_process, 0, sizeof(process_t));
1.1 root 6489:
6490: current_psp = psp->parent_psp;
6491: retval = ret;
1.1.1.23 root 6492: msdos_sda_update(current_psp);
1.1 root 6493: }
6494:
6495: // drive
6496:
1.1.1.42 root 6497: int pcbios_update_drive_param(int drive_num, int force_update);
6498:
1.1 root 6499: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
6500: {
1.1.1.41 root 6501: if(!(drive_num >= 0 && drive_num < 26)) {
6502: return(0);
6503: }
1.1.1.42 root 6504: pcbios_update_drive_param(drive_num, force_update);
6505:
6506: drive_param_t *drive_param = &drive_params[drive_num];
1.1 root 6507: *seg = DPB_TOP >> 4;
6508: *ofs = sizeof(dpb_t) * drive_num;
6509: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
6510:
6511: memset(dpb, 0, sizeof(dpb_t));
6512:
1.1.1.41 root 6513: dpb->drive_num = drive_num;
6514: dpb->unit_num = drive_num;
1.1.1.42 root 6515:
6516: if(drive_param->valid) {
6517: DISK_GEOMETRY *geo = &drive_param->geometry;
6518:
6519: dpb->bytes_per_sector = (UINT16)geo->BytesPerSector;
6520: dpb->highest_sector_num = (UINT8)(geo->SectorsPerTrack - 1);
6521: dpb->highest_cluster_num = (UINT16)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6522: dpb->maximum_cluster_num = (UINT32)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6523: switch(geo->MediaType) {
6524: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6525: dpb->media_type = 0xff;
6526: break;
6527: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6528: dpb->media_type = 0xfe;
6529: break;
6530: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6531: dpb->media_type = 0xfd;
6532: break;
6533: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6534: dpb->media_type = 0xfc;
6535: break;
6536: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6537: case F3_1Pt2_512:
6538: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6539: case F5_720_512:
6540: dpb->media_type = 0xf9;
6541: break;
6542: case FixedMedia: // hard disk
6543: case RemovableMedia:
6544: case Unknown:
6545: dpb->media_type = 0xf8;
6546: break;
6547: default:
6548: dpb->media_type = 0xf0;
6549: break;
6550: }
6551: }
1.1.1.41 root 6552: dpb->next_dpb_ofs = (drive_num == 25) ? 0xffff : *ofs + sizeof(dpb_t);
6553: dpb->next_dpb_seg = (drive_num == 25) ? 0xffff : *seg;
1.1.1.42 root 6554: dpb->info_sector = 0xffff;
6555: dpb->backup_boot_sector = 0xffff;
6556: dpb->free_clusters = 0xffff;
6557: dpb->free_search_cluster = 0xffffffff;
6558:
6559: return(drive_param->valid);
1.1 root 6560: }
6561:
6562: // pc bios
6563:
1.1.1.35 root 6564: #ifdef USE_SERVICE_THREAD
6565: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress)
6566: {
6567: #if defined(HAS_I386)
6568: if(m_SF != 0) {
6569: m_SF = 0;
1.1.1.49! root 6570: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4
1.1.1.35 root 6571: } else {
6572: m_SF = 1;
1.1.1.49! root 6573: mem[DUMMY_TOP + 0x15] = 0x78; // js -4
1.1.1.35 root 6574: }
6575: #else
6576: if(m_SignVal < 0) {
6577: m_SignVal = 0;
1.1.1.49! root 6578: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4
1.1.1.35 root 6579: } else {
6580: m_SignVal = -1;
1.1.1.49! root 6581: mem[DUMMY_TOP + 0x15] = 0x78; // js -4
1.1.1.35 root 6582: }
6583: #endif
1.1.1.49! root 6584: i386_call_far(DUMMY_TOP >> 4, 0x0013);
1.1.1.35 root 6585: in_service = true;
6586: service_exit = false;
6587: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL));
6588: }
6589:
6590: void finish_service_loop()
6591: {
6592: if(in_service && service_exit) {
6593: #if defined(HAS_I386)
6594: if(m_SF != 0) {
6595: m_SF = 0;
6596: } else {
6597: m_SF = 1;
6598: }
6599: #else
6600: if(m_SignVal < 0) {
6601: m_SignVal = 0;
6602: } else {
6603: m_SignVal = -1;
6604: }
6605: #endif
6606: in_service = false;
6607: }
6608: }
6609: #endif
6610:
1.1.1.19 root 6611: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
6612: {
6613: static unsigned __int64 start_msec_since_midnight = 0;
6614: static unsigned __int64 start_msec_since_hostboot = 0;
6615:
6616: if(start_msec_since_midnight == 0) {
6617: SYSTEMTIME time;
6618: GetLocalTime(&time);
6619: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
6620: start_msec_since_hostboot = cur_msec;
6621: }
6622: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
6623: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
6624: return (UINT32)tick;
6625: }
6626:
6627: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
6628: {
6629: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
6630: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
6631:
6632: if(prev_tick > next_tick) {
6633: mem[0x470] = 1;
6634: }
6635: *(UINT32 *)(mem + 0x46c) = next_tick;
6636: }
6637:
1.1.1.14 root 6638: inline void pcbios_irq0()
6639: {
6640: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 6641: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 6642: }
6643:
1.1.1.16 root 6644: int pcbios_get_text_vram_address(int page)
1.1 root 6645: {
6646: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6647: return TEXT_VRAM_TOP;
1.1 root 6648: } else {
1.1.1.14 root 6649: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 6650: }
6651: }
6652:
1.1.1.16 root 6653: int pcbios_get_shadow_buffer_address(int page)
1.1 root 6654: {
1.1.1.14 root 6655: if(!int_10h_feh_called) {
1.1.1.16 root 6656: return pcbios_get_text_vram_address(page);
1.1.1.14 root 6657: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6658: return SHADOW_BUF_TOP;
6659: } else {
1.1.1.14 root 6660: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 6661: }
6662: }
6663:
1.1.1.16 root 6664: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 6665: {
1.1.1.16 root 6666: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 6667: }
6668:
1.1.1.16 root 6669: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 6670: {
1.1.1.14 root 6671: // clear the existing screen, not just the new one
6672: int clr_height = max(height, scr_height);
6673:
1.1.1.16 root 6674: if(scr_width != width || scr_height != height) {
6675: change_console_size(width, height);
1.1.1.14 root 6676: }
6677: mem[0x462] = 0;
6678: *(UINT16 *)(mem + 0x44e) = 0;
6679:
1.1.1.16 root 6680: text_vram_top_address = pcbios_get_text_vram_address(0);
6681: text_vram_end_address = text_vram_top_address + width * height * 2;
6682: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
6683: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 6684:
1.1.1.23 root 6685: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 6686: if(clr_screen) {
1.1.1.14 root 6687: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
6688: mem[ofs++] = 0x20;
6689: mem[ofs++] = 0x07;
6690: }
6691:
1.1.1.35 root 6692: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6693: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6694: #endif
1.1.1.14 root 6695: for(int y = 0; y < clr_height; y++) {
6696: for(int x = 0; x < scr_width; x++) {
6697: SCR_BUF(y,x).Char.AsciiChar = ' ';
6698: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 6699: }
6700: }
6701: SMALL_RECT rect;
1.1.1.14 root 6702: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
6703: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6704: vram_length_char = vram_last_length_char = 0;
6705: vram_length_attr = vram_last_length_attr = 0;
1.1.1.35 root 6706: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6707: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6708: #endif
1.1 root 6709: }
1.1.1.14 root 6710: COORD co;
6711: co.X = 0;
6712: co.Y = scr_top;
6713: SetConsoleCursorPosition(hStdout, co);
6714: cursor_moved = true;
6715: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 6716: }
6717:
1.1.1.36 root 6718: void pcbios_update_cursor_position()
6719: {
6720: CONSOLE_SCREEN_BUFFER_INFO csbi;
6721: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
6722: if(!restore_console_on_exit) {
6723: scr_top = csbi.srWindow.Top;
6724: }
6725: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
6726: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
6727: }
6728:
1.1.1.16 root 6729: inline void pcbios_int_10h_00h()
6730: {
6731: switch(REG8(AL) & 0x7f) {
6732: case 0x70: // v-text mode
6733: case 0x71: // extended cga v-text mode
6734: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
6735: break;
6736: default:
6737: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
6738: break;
6739: }
6740: if(REG8(AL) & 0x80) {
6741: mem[0x487] |= 0x80;
6742: } else {
6743: mem[0x487] &= ~0x80;
6744: }
6745: mem[0x449] = REG8(AL) & 0x7f;
6746: }
6747:
1.1 root 6748: inline void pcbios_int_10h_01h()
6749: {
1.1.1.13 root 6750: mem[0x460] = REG8(CL);
6751: mem[0x461] = REG8(CH);
1.1.1.14 root 6752:
1.1.1.23 root 6753: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6754: CONSOLE_CURSOR_INFO ci;
6755: GetConsoleCursorInfo(hStdout, &ci);
6756: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
6757: // if(ci.bVisible) {
6758: int lines = max(8, REG8(CL) + 1);
6759: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
6760: // }
6761: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 6762: }
6763:
6764: inline void pcbios_int_10h_02h()
6765: {
1.1.1.14 root 6766: // continuously setting the cursor effectively stops it blinking
6767: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 6768: COORD co;
6769: co.X = REG8(DL);
1.1.1.14 root 6770: co.Y = REG8(DH) + scr_top;
6771:
6772: // some programs hide the cursor by moving it off screen
6773: static bool hidden = false;
1.1.1.23 root 6774: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6775: CONSOLE_CURSOR_INFO ci;
6776: GetConsoleCursorInfo(hStdout, &ci);
6777:
6778: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
6779: if(ci.bVisible) {
6780: ci.bVisible = FALSE;
6781: // SetConsoleCursorInfo(hStdout, &ci);
6782: hidden = true;
6783: }
6784: } else if(hidden) {
6785: if(!ci.bVisible) {
6786: ci.bVisible = TRUE;
6787: // SetConsoleCursorInfo(hStdout, &ci);
6788: }
6789: hidden = false;
6790: }
1.1 root 6791: }
1.1.1.14 root 6792: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
6793: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 6794: }
6795:
6796: inline void pcbios_int_10h_03h()
6797: {
1.1.1.14 root 6798: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6799: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6800: REG8(CL) = mem[0x460];
6801: REG8(CH) = mem[0x461];
6802: }
6803:
6804: inline void pcbios_int_10h_05h()
6805: {
1.1.1.14 root 6806: if(REG8(AL) >= vram_pages) {
6807: return;
6808: }
6809: if(mem[0x462] != REG8(AL)) {
6810: vram_flush();
6811:
1.1.1.23 root 6812: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6813: SMALL_RECT rect;
1.1.1.14 root 6814: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6815: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6816:
1.1.1.16 root 6817: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 6818: for(int x = 0; x < scr_width; x++) {
6819: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6820: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6821: }
6822: }
1.1.1.16 root 6823: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 6824: for(int x = 0; x < scr_width; x++) {
6825: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
6826: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 6827: }
6828: }
1.1.1.14 root 6829: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6830:
6831: COORD co;
1.1.1.14 root 6832: co.X = mem[0x450 + REG8(AL) * 2];
6833: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
6834: if(co.Y < scr_top + scr_height) {
6835: SetConsoleCursorPosition(hStdout, co);
6836: }
1.1 root 6837: }
1.1.1.14 root 6838: mem[0x462] = REG8(AL);
6839: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
6840: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 6841: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 6842: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 6843: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 6844: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 6845: }
6846:
6847: inline void pcbios_int_10h_06h()
6848: {
1.1.1.14 root 6849: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6850: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6851: return;
6852: }
6853: vram_flush();
6854:
1.1.1.23 root 6855: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6856: SMALL_RECT rect;
1.1.1.14 root 6857: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6858: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6859:
6860: int right = min(REG8(DL), scr_width - 1);
6861: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6862:
6863: if(REG8(AL) == 0) {
1.1.1.14 root 6864: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6865: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6866: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6867: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6868: }
6869: }
6870: } else {
1.1.1.14 root 6871: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 6872: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6873: if(y2 <= bottom) {
6874: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6875: } else {
1.1.1.14 root 6876: SCR_BUF(y,x).Char.AsciiChar = ' ';
6877: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6878: }
1.1.1.14 root 6879: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6880: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6881: }
6882: }
6883: }
1.1.1.14 root 6884: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6885: }
6886:
6887: inline void pcbios_int_10h_07h()
6888: {
1.1.1.14 root 6889: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6890: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6891: return;
6892: }
6893: vram_flush();
6894:
1.1.1.23 root 6895: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6896: SMALL_RECT rect;
1.1.1.14 root 6897: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6898: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6899:
6900: int right = min(REG8(DL), scr_width - 1);
6901: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6902:
6903: if(REG8(AL) == 0) {
1.1.1.14 root 6904: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6905: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6906: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6907: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6908: }
6909: }
6910: } else {
1.1.1.14 root 6911: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 6912: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6913: if(y2 >= REG8(CH)) {
6914: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6915: } else {
1.1.1.14 root 6916: SCR_BUF(y,x).Char.AsciiChar = ' ';
6917: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6918: }
1.1.1.14 root 6919: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6920: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6921: }
6922: }
6923: }
1.1.1.14 root 6924: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6925: }
6926:
6927: inline void pcbios_int_10h_08h()
6928: {
6929: COORD co;
6930: DWORD num;
6931:
1.1.1.14 root 6932: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6933: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6934:
6935: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6936: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6937: co.Y += scr_top;
6938: vram_flush();
1.1 root 6939: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
6940: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
6941: REG8(AL) = scr_char[0];
6942: REG8(AH) = scr_attr[0];
6943: } else {
1.1.1.16 root 6944: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 6945: }
6946: }
6947:
6948: inline void pcbios_int_10h_09h()
6949: {
6950: COORD co;
6951:
1.1.1.14 root 6952: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6953: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6954:
1.1.1.16 root 6955: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6956: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6957:
6958: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6959: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6960: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6961: #endif
1.1.1.16 root 6962: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6963: while(dest < end) {
6964: write_text_vram_char(dest - vram, REG8(AL));
6965: mem[dest++] = REG8(AL);
6966: write_text_vram_attr(dest - vram, REG8(BL));
6967: mem[dest++] = REG8(BL);
1.1 root 6968: }
1.1.1.35 root 6969: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6970: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6971: #endif
1.1 root 6972: } else {
1.1.1.14 root 6973: while(dest < end) {
1.1 root 6974: mem[dest++] = REG8(AL);
6975: mem[dest++] = REG8(BL);
6976: }
6977: }
6978: }
6979:
6980: inline void pcbios_int_10h_0ah()
6981: {
6982: COORD co;
6983:
1.1.1.14 root 6984: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6985: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6986:
1.1.1.16 root 6987: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6988: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6989:
6990: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6991: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6992: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6993: #endif
1.1.1.16 root 6994: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6995: while(dest < end) {
6996: write_text_vram_char(dest - vram, REG8(AL));
6997: mem[dest++] = REG8(AL);
6998: dest++;
1.1 root 6999: }
1.1.1.35 root 7000: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7001: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 7002: #endif
1.1 root 7003: } else {
1.1.1.14 root 7004: while(dest < end) {
1.1 root 7005: mem[dest++] = REG8(AL);
7006: dest++;
7007: }
7008: }
7009: }
7010:
1.1.1.40 root 7011: HDC get_console_window_device_context()
7012: {
7013: static HWND hwndFound = 0;
7014:
7015: if(hwndFound == 0) {
7016: // https://support.microsoft.com/en-us/help/124103/how-to-obtain-a-console-window-handle-hwnd
7017: char pszNewWindowTitle[1024];
7018: char pszOldWindowTitle[1024];
7019:
7020: GetConsoleTitle(pszOldWindowTitle, 1024);
7021: wsprintf(pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId());
7022: SetConsoleTitle(pszNewWindowTitle);
7023: Sleep(100);
7024: hwndFound = FindWindow(NULL, pszNewWindowTitle);
7025: SetConsoleTitle(pszOldWindowTitle);
7026: }
7027: return GetDC(hwndFound);
7028: }
7029:
7030: inline void pcbios_int_10h_0ch()
7031: {
7032: HDC hdc = get_console_window_device_context();
7033:
7034: if(hdc != NULL) {
7035: BYTE r = (REG8(AL) & 2) ? 255 : 0;
7036: BYTE g = (REG8(AL) & 4) ? 255 : 0;
7037: BYTE b = (REG8(AL) & 1) ? 255 : 0;
7038:
7039: if(REG8(AL) & 0x80) {
7040: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
7041: if(color != CLR_INVALID) {
7042: r ^= ((DWORD)color & 0x0000ff) ? 255 : 0;
7043: g ^= ((DWORD)color & 0x00ff00) ? 255 : 0;
7044: b ^= ((DWORD)color & 0xff0000) ? 255 : 0;
7045: }
7046: }
7047: SetPixel(hdc, REG16(CX), REG16(DX), RGB(r, g, b));
7048: }
7049: }
7050:
7051: inline void pcbios_int_10h_0dh()
7052: {
7053: HDC hdc = get_console_window_device_context();
7054: BYTE r = 0;
7055: BYTE g = 0;
7056: BYTE b = 0;
7057:
7058: if(hdc != NULL) {
7059: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
7060: if(color != CLR_INVALID) {
7061: r = ((DWORD)color & 0x0000ff) ? 255 : 0;
7062: g = ((DWORD)color & 0x00ff00) ? 255 : 0;
7063: b = ((DWORD)color & 0xff0000) ? 255 : 0;
7064: }
7065: }
7066: REG8(AL) = ((b != 0) ? 1 : 0) | ((r != 0) ? 2 : 0) | ((g != 0) ? 4 : 0);
7067: }
7068:
1.1 root 7069: inline void pcbios_int_10h_0eh()
7070: {
1.1.1.14 root 7071: DWORD num;
7072: COORD co;
7073:
7074: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
7075: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
7076:
7077: if(REG8(AL) == 7) {
7078: //MessageBeep(-1);
7079: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
7080: if(REG8(AL) == 10) {
7081: vram_flush();
7082: }
1.1.1.23 root 7083: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 7084: cursor_moved = true;
7085: } else {
1.1.1.16 root 7086: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 7087: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 7088: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7089: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 7090: #endif
1.1.1.16 root 7091: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 7092: write_text_vram_char(dest - vram, REG8(AL));
1.1.1.35 root 7093: #ifdef USE_VRAM_THREAD
1.1.1.14 root 7094: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 7095: #endif
1.1.1.14 root 7096:
1.1.1.23 root 7097: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 7098: if(++co.X == scr_width) {
7099: co.X = 0;
7100: if(++co.Y == scr_height) {
7101: vram_flush();
7102: WriteConsole(hStdout, "\n", 1, &num, NULL);
7103: cursor_moved = true;
7104: }
7105: }
7106: if(!cursor_moved) {
7107: co.Y += scr_top;
7108: SetConsoleCursorPosition(hStdout, co);
7109: cursor_moved = true;
7110: }
7111: }
7112: mem[dest] = REG8(AL);
7113: }
1.1 root 7114: }
7115:
7116: inline void pcbios_int_10h_0fh()
7117: {
7118: REG8(AL) = mem[0x449];
7119: REG8(AH) = mem[0x44a];
7120: REG8(BH) = mem[0x462];
7121: }
7122:
1.1.1.14 root 7123: inline void pcbios_int_10h_11h()
7124: {
7125: switch(REG8(AL)) {
1.1.1.16 root 7126: case 0x01:
1.1.1.14 root 7127: case 0x11:
1.1.1.16 root 7128: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 7129: break;
1.1.1.16 root 7130: case 0x02:
1.1.1.14 root 7131: case 0x12:
1.1.1.16 root 7132: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 7133: break;
1.1.1.16 root 7134: case 0x04:
1.1.1.14 root 7135: case 0x14:
1.1.1.16 root 7136: pcbios_set_console_size(80, 25, true);
7137: break;
7138: case 0x18:
7139: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 7140: break;
7141: case 0x30:
7142: SREG(ES) = 0;
7143: i386_load_segment_descriptor(ES);
7144: REG16(BP) = 0;
7145: REG16(CX) = mem[0x485];
7146: REG8(DL) = mem[0x484];
7147: break;
7148: }
7149: }
7150:
7151: inline void pcbios_int_10h_12h()
7152: {
1.1.1.16 root 7153: switch(REG8(BL)) {
7154: case 0x10:
1.1.1.14 root 7155: REG16(BX) = 0x0003;
7156: REG16(CX) = 0x0009;
1.1.1.16 root 7157: break;
1.1.1.14 root 7158: }
7159: }
7160:
1.1 root 7161: inline void pcbios_int_10h_13h()
7162: {
1.1.1.3 root 7163: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 7164: COORD co;
7165: DWORD num;
7166:
7167: co.X = REG8(DL);
1.1.1.14 root 7168: co.Y = REG8(DH) + scr_top;
7169:
7170: vram_flush();
1.1 root 7171:
7172: switch(REG8(AL)) {
7173: case 0x00:
7174: case 0x01:
7175: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7176: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7177: CONSOLE_SCREEN_BUFFER_INFO csbi;
7178: GetConsoleScreenBufferInfo(hStdout, &csbi);
7179: SetConsoleCursorPosition(hStdout, co);
7180:
7181: if(csbi.wAttributes != REG8(BL)) {
7182: SetConsoleTextAttribute(hStdout, REG8(BL));
7183: }
1.1.1.14 root 7184: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
7185:
1.1 root 7186: if(csbi.wAttributes != REG8(BL)) {
7187: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7188: }
7189: if(REG8(AL) == 0x00) {
1.1.1.15 root 7190: if(!restore_console_on_exit) {
7191: GetConsoleScreenBufferInfo(hStdout, &csbi);
7192: scr_top = csbi.srWindow.Top;
7193: }
1.1.1.14 root 7194: co.X = mem[0x450 + REG8(BH) * 2];
7195: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 7196: SetConsoleCursorPosition(hStdout, co);
7197: } else {
7198: cursor_moved = true;
7199: }
7200: } else {
1.1.1.3 root 7201: m_CF = 1;
1.1 root 7202: }
7203: break;
7204: case 0x02:
7205: case 0x03:
7206: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7207: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7208: CONSOLE_SCREEN_BUFFER_INFO csbi;
7209: GetConsoleScreenBufferInfo(hStdout, &csbi);
7210: SetConsoleCursorPosition(hStdout, co);
7211:
7212: WORD wAttributes = csbi.wAttributes;
7213: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
7214: if(wAttributes != mem[ofs + 1]) {
7215: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
7216: wAttributes = mem[ofs + 1];
7217: }
1.1.1.14 root 7218: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 7219: }
7220: if(csbi.wAttributes != wAttributes) {
7221: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7222: }
7223: if(REG8(AL) == 0x02) {
1.1.1.14 root 7224: co.X = mem[0x450 + REG8(BH) * 2];
7225: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 7226: SetConsoleCursorPosition(hStdout, co);
7227: } else {
7228: cursor_moved = true;
7229: }
7230: } else {
1.1.1.3 root 7231: m_CF = 1;
1.1 root 7232: }
7233: break;
7234: case 0x10:
7235: case 0x11:
7236: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7237: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7238: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
7239: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
7240: for(int i = 0; i < num; i++) {
7241: mem[ofs++] = scr_char[i];
7242: mem[ofs++] = scr_attr[i];
1.1.1.45 root 7243: if(REG8(AL) & 0x01) {
1.1 root 7244: mem[ofs++] = 0;
7245: mem[ofs++] = 0;
7246: }
7247: }
7248: } else {
1.1.1.16 root 7249: 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 7250: mem[ofs++] = mem[src++];
7251: mem[ofs++] = mem[src++];
1.1.1.45 root 7252: if(REG8(AL) & 0x01) {
1.1 root 7253: mem[ofs++] = 0;
7254: mem[ofs++] = 0;
7255: }
1.1.1.14 root 7256: if(++co.X == scr_width) {
7257: if(++co.Y == scr_height) {
1.1 root 7258: break;
7259: }
7260: co.X = 0;
7261: }
7262: }
7263: }
7264: break;
1.1.1.45 root 7265: case 0x12: // ???
7266: case 0x13: // ???
1.1 root 7267: case 0x20:
7268: case 0x21:
7269: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7270: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 7271: int len = min(REG16(CX), scr_width * scr_height);
7272: for(int i = 0; i < len; i++) {
1.1 root 7273: scr_char[i] = mem[ofs++];
7274: scr_attr[i] = mem[ofs++];
1.1.1.45 root 7275: if(REG8(AL) & 0x01) {
1.1 root 7276: ofs += 2;
7277: }
7278: }
1.1.1.14 root 7279: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7280: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7281: } else {
1.1.1.16 root 7282: 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 7283: mem[dest++] = mem[ofs++];
7284: mem[dest++] = mem[ofs++];
1.1.1.45 root 7285: if(REG8(AL) & 0x01) {
1.1 root 7286: ofs += 2;
7287: }
1.1.1.14 root 7288: if(++co.X == scr_width) {
7289: if(++co.Y == scr_height) {
1.1 root 7290: break;
7291: }
7292: co.X = 0;
7293: }
7294: }
7295: }
7296: break;
7297: default:
1.1.1.22 root 7298: 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 7299: m_CF = 1;
1.1 root 7300: break;
7301: }
7302: }
7303:
1.1.1.30 root 7304: inline void pcbios_int_10h_18h()
7305: {
7306: switch(REG8(AL)) {
7307: case 0x00:
7308: case 0x01:
7309: // REG8(AL) = 0x86;
7310: REG8(AL) = 0x00;
7311: break;
7312: default:
7313: 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));
7314: m_CF = 1;
7315: break;
7316: }
7317: }
7318:
1.1.1.14 root 7319: inline void pcbios_int_10h_1ah()
7320: {
7321: switch(REG8(AL)) {
7322: case 0x00:
7323: REG8(AL) = 0x1a;
7324: REG8(BL) = 0x08;
7325: REG8(BH) = 0x00;
7326: break;
7327: default:
1.1.1.22 root 7328: 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 7329: m_CF = 1;
7330: break;
7331: }
7332: }
7333:
1.1 root 7334: inline void pcbios_int_10h_1dh()
7335: {
7336: switch(REG8(AL)) {
1.1.1.43 root 7337: case 0x00:
7338: // DOS/V Shift Status Line Control is not supported
7339: m_CF = 1;
7340: break;
1.1 root 7341: case 0x01:
7342: break;
7343: case 0x02:
7344: REG16(BX) = 0;
7345: break;
7346: default:
1.1.1.22 root 7347: 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));
7348: m_CF = 1;
7349: break;
7350: }
7351: }
7352:
7353: inline void pcbios_int_10h_4fh()
7354: {
7355: switch(REG8(AL)) {
7356: case 0x00:
7357: REG8(AH) = 0x02; // not supported
7358: break;
7359: case 0x01:
7360: case 0x02:
7361: case 0x03:
7362: case 0x04:
7363: case 0x05:
7364: case 0x06:
7365: case 0x07:
7366: case 0x08:
7367: case 0x09:
7368: case 0x0a:
7369: case 0x0b:
7370: case 0x0c:
7371: REG8(AH) = 0x01; // failed
7372: break;
7373: default:
7374: 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 7375: m_CF = 1;
1.1 root 7376: break;
7377: }
7378: }
7379:
7380: inline void pcbios_int_10h_82h()
7381: {
7382: static UINT8 mode = 0;
7383:
7384: switch(REG8(AL)) {
1.1.1.22 root 7385: case 0x00:
1.1 root 7386: if(REG8(BL) != 0xff) {
7387: mode = REG8(BL);
7388: }
7389: REG8(AL) = mode;
7390: break;
7391: default:
1.1.1.22 root 7392: 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 7393: m_CF = 1;
1.1 root 7394: break;
7395: }
7396: }
7397:
1.1.1.22 root 7398: inline void pcbios_int_10h_83h()
7399: {
7400: static UINT8 mode = 0;
7401:
7402: switch(REG8(AL)) {
7403: case 0x00:
7404: REG16(AX) = 0; // offset???
7405: SREG(ES) = (SHADOW_BUF_TOP >> 4);
7406: i386_load_segment_descriptor(ES);
7407: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
7408: break;
7409: default:
7410: 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));
7411: m_CF = 1;
7412: break;
7413: }
7414: }
7415:
7416: inline void pcbios_int_10h_90h()
7417: {
7418: REG8(AL) = mem[0x449];
7419: }
7420:
7421: inline void pcbios_int_10h_91h()
7422: {
7423: REG8(AL) = 0x04; // VGA
7424: }
7425:
7426: inline void pcbios_int_10h_efh()
7427: {
7428: REG16(DX) = 0xffff;
7429: }
7430:
1.1 root 7431: inline void pcbios_int_10h_feh()
7432: {
7433: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 7434: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 7435: i386_load_segment_descriptor(ES);
1.1.1.8 root 7436: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 7437: }
7438: int_10h_feh_called = true;
7439: }
7440:
7441: inline void pcbios_int_10h_ffh()
7442: {
7443: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 7444: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7445: COORD co;
7446: DWORD num;
7447:
1.1.1.14 root 7448: vram_flush();
7449:
7450: co.X = (REG16(DI) >> 1) % scr_width;
7451: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 7452: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
7453: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 7454: int len;
7455: for(len = 0; ofs < end; len++) {
7456: scr_char[len] = mem[ofs++];
7457: scr_attr[len] = mem[ofs++];
7458: }
7459: co.Y += scr_top;
7460: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7461: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7462: }
7463: int_10h_ffh_called = true;
7464: }
7465:
1.1.1.42 root 7466: int pcbios_update_drive_param(int drive_num, int force_update)
7467: {
7468: if(drive_num >= 0 && drive_num < 26) {
7469: drive_param_t *drive_param = &drive_params[drive_num];
7470:
7471: if(force_update || !drive_param->initialized) {
7472: drive_param->valid = 0;
7473: char dev[64];
7474: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7475:
7476: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7477: if(hFile != INVALID_HANDLE_VALUE) {
7478: DWORD dwSize;
7479: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &drive_param->geometry, sizeof(DISK_GEOMETRY), &dwSize, NULL)) {
7480: drive_param->valid = 1;
7481: }
7482: CloseHandle(hFile);
7483: }
7484: drive_param->initialized = 1;
7485: }
7486: return(drive_param->valid);
7487: }
7488: return(0);
7489: }
7490:
7491: inline void pcbios_int_13h_00h()
7492: {
7493: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7494:
7495: if(pcbios_update_drive_param(drive_num, 1)) {
7496: REG8(AH) = 0x00; // successful completion
7497: } else {
7498: if(REG8(DL) & 0x80) {
7499: REG8(AH) = 0x05; // reset failed (hard disk)
7500: } else {
7501: REG8(AH) = 0x80; // timeout (not ready)
7502: }
7503: m_CF = 1;
7504: }
7505: }
7506:
7507: inline void pcbios_int_13h_02h()
7508: {
7509: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7510:
7511: if(REG8(AL) == 0) {
7512: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7513: m_CF = 1;
7514: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7515: REG8(AH) = 0xff; // sense operation failed (hard disk)
7516: m_CF = 1;
7517: } else {
7518: drive_param_t *drive_param = &drive_params[drive_num];
7519: DISK_GEOMETRY *geo = &drive_param->geometry;
7520: char dev[64];
7521: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7522:
7523: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7524: if(hFile == INVALID_HANDLE_VALUE) {
7525: REG8(AH) = 0xff; // sense operation failed (hard disk)
7526: m_CF = 1;
7527: } else {
7528: UINT32 sector_num = REG8(AL);
7529: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7530: UINT32 head = REG8(DH);
7531: UINT32 sector = REG8(CL) & 0x3f;
7532: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7533: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7534: DWORD dwSize;
7535:
7536: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7537: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7538: // m_CF = 1;
7539: // } else
7540: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7541: REG8(AH) = 0x04; // sector not found/read error
7542: m_CF = 1;
7543: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7544: REG8(AH) = 0x04; // sector not found/read error
7545: m_CF = 1;
7546: } else {
7547: REG8(AH) = 0x00; // successful completion
7548: }
7549: CloseHandle(hFile);
7550: }
7551: }
7552: }
7553:
7554: inline void pcbios_int_13h_03h()
7555: {
7556: // this operation may cause serious damage for drives, so support only floppy disk...
7557: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7558:
7559: if(REG8(AL) == 0) {
7560: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7561: m_CF = 1;
7562: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7563: REG8(AH) = 0xff; // sense operation failed (hard disk)
7564: m_CF = 1;
7565: } else if(!drive_params[drive_num].is_fdd()) {
7566: REG8(AH) = 0xff; // sense operation failed (hard disk)
7567: m_CF = 1;
7568: } else {
7569: drive_param_t *drive_param = &drive_params[drive_num];
7570: DISK_GEOMETRY *geo = &drive_param->geometry;
7571: char dev[64];
7572: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7573:
7574: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7575: if(hFile == INVALID_HANDLE_VALUE) {
7576: REG8(AH) = 0xff; // sense operation failed (hard disk)
7577: m_CF = 1;
7578: } else {
7579: UINT32 sector_num = REG8(AL);
7580: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7581: UINT32 head = REG8(DH);
7582: UINT32 sector = REG8(CL) & 0x3f;
7583: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7584: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7585: DWORD dwSize;
7586:
7587: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7588: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7589: // m_CF = 1;
7590: // } else
7591: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7592: REG8(AH) = 0x04; // sector not found/read error
7593: m_CF = 1;
7594: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7595: REG8(AH) = 0x04; // sector not found/read error
7596: m_CF = 1;
7597: } else {
7598: REG8(AH) = 0x00; // successful completion
7599: }
7600: CloseHandle(hFile);
7601: }
7602: }
7603: }
7604:
7605: inline void pcbios_int_13h_04h()
7606: {
7607: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7608:
7609: if(REG8(AL) == 0) {
7610: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7611: m_CF = 1;
7612: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7613: REG8(AH) = 0xff; // sense operation failed (hard disk)
7614: m_CF = 1;
7615: } else {
7616: drive_param_t *drive_param = &drive_params[drive_num];
7617: DISK_GEOMETRY *geo = &drive_param->geometry;
7618: char dev[64];
7619: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7620:
7621: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7622: if(hFile == INVALID_HANDLE_VALUE) {
7623: REG8(AH) = 0xff; // sense operation failed (hard disk)
7624: m_CF = 1;
7625: } else {
7626: UINT32 sector_num = REG8(AL);
7627: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7628: UINT32 head = REG8(DH);
7629: UINT32 sector = REG8(CL) & 0x3f;
7630: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7631: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7632: DWORD dwSize;
7633: UINT8 *tmp_buffer = (UINT8 *)malloc(sector_num * geo->BytesPerSector);
7634:
7635: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7636: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7637: // m_CF = 1;
7638: // } else
7639: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7640: REG8(AH) = 0x04; // sector not found/read error
7641: m_CF = 1;
7642: } else if(ReadFile(hFile, tmp_buffer, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7643: REG8(AH) = 0x04; // sector not found/read error
7644: m_CF = 1;
7645: } else if(memcmp(mem + buffer_addr, tmp_buffer, sector_num * geo->BytesPerSector) != 0) {
7646: REG8(AH) = 0x05; // data did not verify correctly (TI Professional PC)
7647: m_CF = 1;
7648: } else {
7649: REG8(AH) = 0x00; // successful completion
7650: }
7651: free(tmp_buffer);
7652: CloseHandle(hFile);
7653: }
7654: }
7655: }
7656:
7657: inline void pcbios_int_13h_08h()
7658: {
7659: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7660:
7661: if(pcbios_update_drive_param(drive_num, 1)) {
7662: drive_param_t *drive_param = &drive_params[drive_num];
7663: DISK_GEOMETRY *geo = &drive_param->geometry;
7664:
7665: REG16(AX) = 0x0000;
7666: switch(geo->MediaType) {
7667: case F5_360_512:
7668: case F5_320_512:
7669: case F5_320_1024:
7670: case F5_180_512:
7671: case F5_160_512:
7672: REG8(BL) = 0x01; // 320K/360K disk
7673: break;
7674: case F5_1Pt2_512:
7675: case F3_1Pt2_512:
7676: case F3_1Pt23_1024:
7677: case F5_1Pt23_1024:
7678: REG8(BL) = 0x02; // 1.2M disk
7679: break;
7680: case F3_720_512:
7681: case F3_640_512:
7682: case F5_640_512:
7683: case F5_720_512:
7684: REG8(BL) = 0x03; // 720K disk
7685: break;
7686: case F3_1Pt44_512:
7687: REG8(BL) = 0x04; // 1.44M disk
7688: break;
7689: case F3_2Pt88_512:
7690: REG8(BL) = 0x06; // 2.88M disk
7691: break;
7692: case RemovableMedia:
7693: REG8(BL) = 0x10; // ATAPI Removable Media Device
7694: break;
7695: default:
7696: REG8(BL) = 0x00; // unknown
7697: break;
7698: }
7699: if(REG8(DL) & 0x80) {
7700: switch(GetLogicalDrives() & 0x0c) {
7701: case 0x00: REG8(DL) = 0x00; break;
7702: case 0x04:
7703: case 0x08: REG8(DL) = 0x01; break;
7704: case 0x0c: REG8(DL) = 0x02; break;
7705: }
7706: } else {
7707: switch(GetLogicalDrives() & 0x03) {
7708: case 0x00: REG8(DL) = 0x00; break;
7709: case 0x01:
7710: case 0x02: REG8(DL) = 0x01; break;
7711: case 0x03: REG8(DL) = 0x02; break;
7712: }
7713: }
7714: REG8(DH) = drive_param->head_num();
7715: int cyl = (geo->Cylinders.QuadPart > 0x3ff) ? 0x3ff : geo->Cylinders.QuadPart;
7716: int sec = (geo->SectorsPerTrack > 0x3f) ? 0x3f : geo->SectorsPerTrack;
7717: REG8(CH) = cyl & 0xff;
7718: REG8(CL) = (sec & 0x3f) | ((cyl & 0x300) >> 2);
7719: } else {
7720: REG8(AH) = 0x07;
7721: m_CF = 1;
7722: }
7723: }
7724:
7725: inline void pcbios_int_13h_10h()
7726: {
7727: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7728:
7729: if(pcbios_update_drive_param(drive_num, 1)) {
7730: REG8(AH) = 0x00; // successful completion
7731: } else {
7732: if(REG8(DL) & 0x80) {
7733: REG8(AH) = 0xaa; // drive not ready (hard disk)
7734: } else {
7735: REG8(AH) = 0x80; // timeout (not ready)
7736: }
7737: m_CF = 1;
7738: }
7739: }
7740:
7741: inline void pcbios_int_13h_15h()
7742: {
7743: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7744:
7745: if(pcbios_update_drive_param(drive_num, 1)) {
7746: if(REG8(DL) & 0x80) {
7747: REG8(AH) = 0x02; // floppy (or other removable drive) with change-line support
7748: } else {
7749: REG8(AH) = 0x03; // hard disk
7750: }
7751: } else {
7752: REG8(AH) = 0x00; // no such drive
7753: }
7754: }
7755:
1.1.1.43 root 7756: inline void pcbios_int_13h_41h()
7757: {
7758: if(REG16(BX) == 0x55aa) {
7759: // IBM/MS INT 13 Extensions is not installed
7760: REG8(AH) = 0x01;
7761: m_CF = 1;
7762: } else {
7763: unimplemented_13h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x13, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
7764: REG8(AH) = 0x01;
7765: m_CF = 1;
7766: }
7767: }
7768:
1.1.1.25 root 7769: inline void pcbios_int_14h_00h()
7770: {
1.1.1.29 root 7771: if(REG16(DX) < 4) {
1.1.1.25 root 7772: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
7773: UINT8 selector = sio_read(REG16(DX), 3);
7774: selector &= ~0x3f;
7775: selector |= REG8(AL) & 0x1f;
7776: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
7777: sio_write(REG16(DX), 3, selector | 0x80);
7778: sio_write(REG16(DX), 0, divisor & 0xff);
7779: sio_write(REG16(DX), 1, divisor >> 8);
7780: sio_write(REG16(DX), 3, selector);
7781: REG8(AH) = sio_read(REG16(DX), 5);
7782: REG8(AL) = sio_read(REG16(DX), 6);
7783: } else {
7784: REG8(AH) = 0x80;
7785: }
7786: }
7787:
7788: inline void pcbios_int_14h_01h()
7789: {
1.1.1.29 root 7790: if(REG16(DX) < 4) {
1.1.1.25 root 7791: UINT8 selector = sio_read(REG16(DX), 3);
7792: sio_write(REG16(DX), 3, selector & ~0x80);
7793: sio_write(REG16(DX), 0, REG8(AL));
7794: sio_write(REG16(DX), 3, selector);
7795: REG8(AH) = sio_read(REG16(DX), 5);
7796: } else {
7797: REG8(AH) = 0x80;
7798: }
7799: }
7800:
7801: inline void pcbios_int_14h_02h()
7802: {
1.1.1.29 root 7803: if(REG16(DX) < 4) {
1.1.1.25 root 7804: UINT8 selector = sio_read(REG16(DX), 3);
7805: sio_write(REG16(DX), 3, selector & ~0x80);
7806: REG8(AL) = sio_read(REG16(DX), 0);
7807: sio_write(REG16(DX), 3, selector);
7808: REG8(AH) = sio_read(REG16(DX), 5);
7809: } else {
7810: REG8(AH) = 0x80;
7811: }
7812: }
7813:
7814: inline void pcbios_int_14h_03h()
7815: {
1.1.1.29 root 7816: if(REG16(DX) < 4) {
1.1.1.25 root 7817: REG8(AH) = sio_read(REG16(DX), 5);
7818: REG8(AL) = sio_read(REG16(DX), 6);
7819: } else {
7820: REG8(AH) = 0x80;
7821: }
7822: }
7823:
7824: inline void pcbios_int_14h_04h()
7825: {
1.1.1.29 root 7826: if(REG16(DX) < 4) {
1.1.1.25 root 7827: UINT8 selector = sio_read(REG16(DX), 3);
7828: if(REG8(CH) <= 0x03) {
7829: selector = (selector & ~0x03) | REG8(CH);
7830: }
7831: if(REG8(BL) == 0x00) {
7832: selector &= ~0x04;
7833: } else if(REG8(BL) == 0x01) {
7834: selector |= 0x04;
7835: }
7836: if(REG8(BH) == 0x00) {
7837: selector = (selector & ~0x38) | 0x00;
7838: } else if(REG8(BH) == 0x01) {
7839: selector = (selector & ~0x38) | 0x08;
7840: } else if(REG8(BH) == 0x02) {
7841: selector = (selector & ~0x38) | 0x18;
7842: } else if(REG8(BH) == 0x03) {
7843: selector = (selector & ~0x38) | 0x28;
7844: } else if(REG8(BH) == 0x04) {
7845: selector = (selector & ~0x38) | 0x38;
7846: }
7847: if(REG8(AL) == 0x00) {
7848: selector |= 0x40;
7849: } else if(REG8(AL) == 0x01) {
7850: selector &= ~0x40;
7851: }
7852: if(REG8(CL) <= 0x0b) {
7853: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
7854: UINT16 divisor = 115200 / rate[REG8(CL)];
7855: sio_write(REG16(DX), 3, selector | 0x80);
7856: sio_write(REG16(DX), 0, divisor & 0xff);
7857: sio_write(REG16(DX), 1, divisor >> 8);
7858: }
7859: sio_write(REG16(DX), 3, selector);
7860: REG8(AH) = sio_read(REG16(DX), 5);
7861: REG8(AL) = sio_read(REG16(DX), 6);
7862: } else {
7863: REG8(AH) = 0x80;
7864: }
7865: }
7866:
7867: inline void pcbios_int_14h_05h()
7868: {
1.1.1.29 root 7869: if(REG16(DX) < 4) {
1.1.1.25 root 7870: if(REG8(AL) == 0x00) {
7871: REG8(BL) = sio_read(REG16(DX), 4);
7872: REG8(AH) = sio_read(REG16(DX), 5);
7873: REG8(AL) = sio_read(REG16(DX), 6);
7874: } else if(REG8(AL) == 0x01) {
7875: sio_write(REG16(DX), 4, REG8(BL));
7876: REG8(AH) = sio_read(REG16(DX), 5);
7877: REG8(AL) = sio_read(REG16(DX), 6);
7878: } else {
7879: 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));
7880: }
7881: } else {
7882: REG8(AH) = 0x80;
7883: }
7884: }
7885:
1.1.1.14 root 7886: inline void pcbios_int_15h_10h()
7887: {
1.1.1.22 root 7888: switch(REG8(AL)) {
7889: case 0x00:
1.1.1.14 root 7890: Sleep(10);
1.1.1.35 root 7891: REQUEST_HARDWRE_UPDATE();
1.1.1.22 root 7892: break;
7893: default:
7894: 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 7895: REG8(AH) = 0x86;
7896: m_CF = 1;
7897: }
7898: }
7899:
1.1 root 7900: inline void pcbios_int_15h_23h()
7901: {
7902: switch(REG8(AL)) {
1.1.1.22 root 7903: case 0x00:
1.1.1.8 root 7904: REG8(CL) = cmos_read(0x2d);
7905: REG8(CH) = cmos_read(0x2e);
1.1 root 7906: break;
1.1.1.22 root 7907: case 0x01:
1.1.1.8 root 7908: cmos_write(0x2d, REG8(CL));
7909: cmos_write(0x2e, REG8(CH));
1.1 root 7910: break;
7911: default:
1.1.1.22 root 7912: 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 7913: REG8(AH) = 0x86;
1.1.1.3 root 7914: m_CF = 1;
1.1 root 7915: break;
7916: }
7917: }
7918:
7919: inline void pcbios_int_15h_24h()
7920: {
7921: switch(REG8(AL)) {
1.1.1.22 root 7922: case 0x00:
1.1.1.3 root 7923: i386_set_a20_line(0);
1.1 root 7924: REG8(AH) = 0;
7925: break;
1.1.1.22 root 7926: case 0x01:
1.1.1.3 root 7927: i386_set_a20_line(1);
1.1 root 7928: REG8(AH) = 0;
7929: break;
1.1.1.22 root 7930: case 0x02:
1.1 root 7931: REG8(AH) = 0;
1.1.1.3 root 7932: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 7933: REG16(CX) = 0;
7934: break;
1.1.1.22 root 7935: case 0x03:
1.1 root 7936: REG16(AX) = 0;
7937: REG16(BX) = 0;
7938: break;
1.1.1.22 root 7939: default:
7940: 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));
7941: REG8(AH) = 0x86;
7942: m_CF = 1;
7943: break;
1.1 root 7944: }
7945: }
7946:
7947: inline void pcbios_int_15h_49h()
7948: {
1.1.1.27 root 7949: REG8(AH) = 0x00;
7950: REG8(BL) = 0x00; // DOS/V
1.1 root 7951: }
7952:
1.1.1.22 root 7953: inline void pcbios_int_15h_50h()
7954: {
7955: switch(REG8(AL)) {
7956: case 0x00:
7957: case 0x01:
7958: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
7959: REG8(AH) = 0x01; // invalid font type in bh
7960: m_CF = 1;
1.1.1.27 root 7961: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 7962: REG8(AH) = 0x02; // bl not zero
7963: m_CF = 1;
7964: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
7965: REG8(AH) = 0x04; // invalid code page
7966: m_CF = 1;
1.1.1.27 root 7967: } else if(REG8(AL) == 0x01) {
7968: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 7969: m_CF = 1;
1.1.1.27 root 7970: } else {
1.1.1.49! root 7971: // dummy font read routine is at fffc:000d
! 7972: SREG(ES) = DUMMY_TOP >> 4;
1.1.1.27 root 7973: i386_load_segment_descriptor(ES);
1.1.1.32 root 7974: REG16(BX) = 0x000d;
1.1.1.27 root 7975: REG8(AH) = 0x00; // success
1.1.1.22 root 7976: }
7977: break;
7978: default:
7979: 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));
7980: REG8(AH) = 0x86;
7981: m_CF = 1;
7982: break;
7983: }
7984: }
7985:
1.1.1.30 root 7986: inline void pcbios_int_15h_53h()
7987: {
7988: switch(REG8(AL)) {
7989: case 0x00:
7990: // APM is not installed
7991: REG8(AH) = 0x86;
7992: m_CF = 1;
7993: break;
7994: default:
7995: 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));
7996: REG8(AH) = 0x86;
7997: m_CF = 1;
7998: break;
7999: }
8000: }
8001:
1.1.1.43 root 8002: inline void pcbios_int_15h_84h()
8003: {
8004: // joystick support (from DOSBox)
8005: switch(REG16(DX)) {
8006: case 0x00:
8007: REG16(AX) = 0x00f0;
8008: REG16(DX) = 0x0201;
8009: m_CF = 1;
8010: break;
8011: case 0x01:
8012: REG16(AX) = REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
8013: m_CF = 1;
8014: break;
8015: default:
8016: 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));
8017: REG8(AH) = 0x86;
8018: m_CF = 1;
8019: break;
8020: }
8021: }
1.1.1.35 root 8022:
8023: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID)
1.1 root 8024: {
8025: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 8026: UINT32 msec = usec / 1000;
8027:
1.1.1.35 root 8028: while(msec && !m_halted) {
1.1.1.14 root 8029: UINT32 tmp = min(msec, 100);
8030: if(msec - tmp < 10) {
8031: tmp = msec;
8032: }
8033: Sleep(tmp);
8034: msec -= tmp;
8035: }
1.1.1.35 root 8036:
8037: #ifdef USE_SERVICE_THREAD
8038: service_exit = true;
8039: #endif
8040: return(0);
8041: }
8042:
8043: inline void pcbios_int_15h_86h()
8044: {
8045: if(!(REG16(CX) == 0 && REG16(DX) == 0)) {
8046: #ifdef USE_SERVICE_THREAD
8047: start_service_loop(pcbios_int_15h_86h_thread);
8048: #else
8049: pcbios_int_15h_86h_thread(NULL);
8050: REQUEST_HARDWRE_UPDATE();
8051: #endif
8052: }
1.1 root 8053: }
8054:
8055: inline void pcbios_int_15h_87h()
8056: {
8057: // copy extended memory (from DOSBox)
8058: int len = REG16(CX) * 2;
1.1.1.3 root 8059: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 8060: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
8061: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
8062: memcpy(mem + dst, mem + src, len);
8063: REG16(AX) = 0x00;
8064: }
8065:
8066: inline void pcbios_int_15h_88h()
8067: {
1.1.1.17 root 8068: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 8069: }
8070:
8071: inline void pcbios_int_15h_89h()
8072: {
1.1.1.21 root 8073: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 8074: // switch to protected mode (from DOSBox)
8075: write_io_byte(0x20, 0x10);
8076: write_io_byte(0x21, REG8(BH));
8077: write_io_byte(0x21, 0x00);
8078: write_io_byte(0xa0, 0x10);
8079: write_io_byte(0xa1, REG8(BL));
8080: write_io_byte(0xa1, 0x00);
1.1.1.3 root 8081: i386_set_a20_line(1);
8082: int ofs = SREG_BASE(ES) + REG16(SI);
8083: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
8084: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
8085: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
8086: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
8087: #if defined(HAS_I386)
8088: m_cr[0] |= 1;
8089: #else
8090: m_msw |= 1;
8091: #endif
8092: SREG(DS) = 0x18;
8093: SREG(ES) = 0x20;
8094: SREG(SS) = 0x28;
8095: i386_load_segment_descriptor(DS);
8096: i386_load_segment_descriptor(ES);
8097: i386_load_segment_descriptor(SS);
1.1.1.21 root 8098: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 8099: REG16(SP) += 6;
1.1.1.3 root 8100: #if defined(HAS_I386)
1.1.1.21 root 8101: UINT32 flags = get_flags();
8102: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
8103: set_flags(flags);
1.1.1.3 root 8104: #else
1.1.1.21 root 8105: UINT32 flags = CompressFlags();
8106: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
8107: ExpandFlags(flags);
1.1.1.3 root 8108: #endif
1.1 root 8109: REG16(AX) = 0x00;
1.1.1.21 root 8110: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 8111: #else
1.1.1.21 root 8112: // i86/i186/v30: protected mode is not supported
1.1 root 8113: REG8(AH) = 0x86;
1.1.1.3 root 8114: m_CF = 1;
1.1 root 8115: #endif
8116: }
8117:
1.1.1.21 root 8118: inline void pcbios_int_15h_8ah()
8119: {
8120: UINT32 size = MAX_MEM - 0x100000;
8121: REG16(AX) = size & 0xffff;
8122: REG16(DX) = size >> 16;
8123: }
8124:
1.1.1.3 root 8125: #if defined(HAS_I386)
1.1 root 8126: inline void pcbios_int_15h_c9h()
8127: {
8128: REG8(AH) = 0x00;
8129: REG8(CH) = cpu_type;
8130: REG8(CL) = cpu_step;
8131: }
1.1.1.3 root 8132: #endif
1.1 root 8133:
8134: inline void pcbios_int_15h_cah()
8135: {
8136: switch(REG8(AL)) {
1.1.1.22 root 8137: case 0x00:
1.1 root 8138: if(REG8(BL) > 0x3f) {
8139: REG8(AH) = 0x03;
1.1.1.3 root 8140: m_CF = 1;
1.1 root 8141: } else if(REG8(BL) < 0x0e) {
8142: REG8(AH) = 0x04;
1.1.1.3 root 8143: m_CF = 1;
1.1 root 8144: } else {
1.1.1.8 root 8145: REG8(CL) = cmos_read(REG8(BL));
1.1 root 8146: }
8147: break;
1.1.1.22 root 8148: case 0x01:
1.1 root 8149: if(REG8(BL) > 0x3f) {
8150: REG8(AH) = 0x03;
1.1.1.3 root 8151: m_CF = 1;
1.1 root 8152: } else if(REG8(BL) < 0x0e) {
8153: REG8(AH) = 0x04;
1.1.1.3 root 8154: m_CF = 1;
1.1 root 8155: } else {
1.1.1.8 root 8156: cmos_write(REG8(BL), REG8(CL));
1.1 root 8157: }
8158: break;
8159: default:
1.1.1.22 root 8160: 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 8161: REG8(AH) = 0x86;
1.1.1.3 root 8162: m_CF = 1;
1.1 root 8163: break;
8164: }
8165: }
8166:
1.1.1.22 root 8167: inline void pcbios_int_15h_e8h()
1.1.1.17 root 8168: {
1.1.1.22 root 8169: switch(REG8(AL)) {
8170: #if defined(HAS_I386)
8171: case 0x01:
8172: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
8173: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
8174: break;
1.1.1.17 root 8175: #endif
1.1.1.22 root 8176: default:
8177: 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));
8178: REG8(AH) = 0x86;
8179: m_CF = 1;
8180: break;
8181: }
8182: }
1.1.1.17 root 8183:
1.1.1.33 root 8184: void pcbios_update_key_code(bool wait)
1.1 root 8185: {
1.1.1.32 root 8186: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8187: #ifdef USE_SERVICE_THREAD
8188: EnterCriticalSection(&key_buf_crit_sect);
8189: #endif
8190: bool empty = key_buf_char->empty();
8191: #ifdef USE_SERVICE_THREAD
8192: LeaveCriticalSection(&key_buf_crit_sect);
8193: #endif
8194: if(empty) {
1.1.1.32 root 8195: if(!update_key_buffer()) {
1.1.1.33 root 8196: if(wait) {
1.1.1.32 root 8197: Sleep(10);
8198: } else {
8199: maybe_idle();
8200: }
1.1.1.14 root 8201: }
8202: }
1.1.1.34 root 8203: }
8204: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8205: #ifdef USE_SERVICE_THREAD
8206: EnterCriticalSection(&key_buf_crit_sect);
8207: #endif
1.1.1.32 root 8208: if(key_buf_char->count() != 0) {
1.1.1.41 root 8209: int key_char = key_buf_char->read();
8210: int key_scan = key_buf_scan->read();
8211: key_code = key_char << 0;
8212: key_code |= key_scan << 8;
1.1.1.35 root 8213: key_recv = 0x0000ffff;
1.1.1.41 root 8214: // write to bottom of key buffer
8215: mem[0x43c] = (UINT8)key_char;
8216: mem[0x43d] = (UINT8)key_scan;
1.1.1.32 root 8217: }
8218: if(key_buf_char->count() != 0) {
1.1.1.41 root 8219: int key_char = key_buf_char->read();
8220: int key_scan = key_buf_scan->read();
8221: key_code |= key_char << 16;
8222: key_code |= key_scan << 24;
1.1.1.33 root 8223: key_recv |= 0xffff0000;
1.1.1.41 root 8224: // write to bottom of key buffer
8225: mem[0x43c] = (UINT8)key_char;
8226: mem[0x43d] = (UINT8)key_scan;
1.1.1.32 root 8227: }
1.1.1.35 root 8228: #ifdef USE_SERVICE_THREAD
8229: LeaveCriticalSection(&key_buf_crit_sect);
8230: #endif
1.1 root 8231: }
8232: }
8233:
1.1.1.35 root 8234: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID)
1.1 root 8235: {
1.1.1.33 root 8236: while(key_recv == 0 && !m_halted) {
8237: pcbios_update_key_code(true);
1.1 root 8238: }
1.1.1.33 root 8239: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
8240: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
8241: if(REG8(AH) == 0x10) {
8242: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
8243: } else {
8244: key_code = ((key_code >> 16) & 0xff00);
8245: }
8246: key_recv >>= 16;
1.1 root 8247: }
8248: }
8249: REG16(AX) = key_code & 0xffff;
8250: key_code >>= 16;
1.1.1.33 root 8251: key_recv >>= 16;
1.1.1.35 root 8252:
8253: #ifdef USE_SERVICE_THREAD
8254: service_exit = true;
8255: #endif
8256: return(0);
8257: }
8258:
8259: inline void pcbios_int_16h_00h()
8260: {
8261: #ifdef USE_SERVICE_THREAD
8262: start_service_loop(pcbios_int_16h_00h_thread);
8263: #else
8264: pcbios_int_16h_00h_thread(NULL);
8265: REQUEST_HARDWRE_UPDATE();
8266: #endif
1.1 root 8267: }
8268:
8269: inline void pcbios_int_16h_01h()
8270: {
1.1.1.33 root 8271: if(key_recv == 0) {
8272: pcbios_update_key_code(false);
1.1.1.5 root 8273: }
1.1.1.33 root 8274: if(key_recv != 0) {
8275: UINT32 key_code_tmp = key_code;
8276: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
8277: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
8278: if(REG8(AH) == 0x11) {
8279: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
8280: } else {
8281: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
8282: }
8283: }
1.1 root 8284: }
1.1.1.5 root 8285: REG16(AX) = key_code_tmp & 0xffff;
1.1.1.3 root 8286: #if defined(HAS_I386)
1.1.1.33 root 8287: m_ZF = 0;
8288: #else
8289: m_ZeroVal = 1;
8290: #endif
8291: } else {
8292: #if defined(HAS_I386)
8293: m_ZF = 1;
1.1.1.3 root 8294: #else
1.1.1.33 root 8295: m_ZeroVal = 0;
1.1.1.3 root 8296: #endif
1.1.1.33 root 8297: }
1.1 root 8298: }
8299:
8300: inline void pcbios_int_16h_02h()
8301: {
8302: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
8303: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
8304: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
8305: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
8306: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
8307: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
8308: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
8309: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
8310: }
8311:
8312: inline void pcbios_int_16h_03h()
8313: {
8314: static UINT16 status = 0;
8315:
8316: switch(REG8(AL)) {
8317: case 0x05:
8318: status = REG16(BX);
8319: break;
8320: case 0x06:
8321: REG16(BX) = status;
8322: break;
8323: default:
1.1.1.3 root 8324: m_CF = 1;
1.1 root 8325: break;
8326: }
8327: }
8328:
8329: inline void pcbios_int_16h_05h()
8330: {
1.1.1.32 root 8331: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8332: #ifdef USE_SERVICE_THREAD
8333: EnterCriticalSection(&key_buf_crit_sect);
8334: #endif
1.1.1.32 root 8335: key_buf_char->write(REG8(CL));
8336: key_buf_scan->write(REG8(CH));
1.1.1.35 root 8337: #ifdef USE_SERVICE_THREAD
8338: LeaveCriticalSection(&key_buf_crit_sect);
8339: #endif
1.1.1.32 root 8340: }
1.1 root 8341: REG8(AL) = 0x00;
8342: }
8343:
8344: inline void pcbios_int_16h_12h()
8345: {
8346: pcbios_int_16h_02h();
8347:
8348: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
8349: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
8350: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
8351: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
8352: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
8353: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
8354: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
8355: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
8356: }
8357:
8358: inline void pcbios_int_16h_13h()
8359: {
8360: static UINT16 status = 0;
8361:
8362: switch(REG8(AL)) {
8363: case 0x00:
8364: status = REG16(DX);
8365: break;
8366: case 0x01:
8367: REG16(DX) = status;
8368: break;
8369: default:
1.1.1.22 root 8370: 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 8371: m_CF = 1;
1.1 root 8372: break;
8373: }
8374: }
8375:
8376: inline void pcbios_int_16h_14h()
8377: {
8378: static UINT8 status = 0;
8379:
8380: switch(REG8(AL)) {
8381: case 0x00:
8382: case 0x01:
8383: status = REG8(AL);
8384: break;
8385: case 0x02:
8386: REG8(AL) = status;
8387: break;
8388: default:
1.1.1.22 root 8389: 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 8390: m_CF = 1;
1.1 root 8391: break;
8392: }
8393: }
8394:
1.1.1.24 root 8395: inline void pcbios_int_16h_55h()
8396: {
8397: switch(REG8(AL)) {
8398: case 0x00:
8399: // keyboard tsr is not present
8400: break;
8401: case 0xfe:
8402: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
8403: break;
8404: case 0xff:
8405: break;
8406: default:
8407: 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));
8408: m_CF = 1;
8409: break;
8410: }
8411: }
8412:
1.1.1.30 root 8413: inline void pcbios_int_16h_6fh()
8414: {
8415: switch(REG8(AL)) {
8416: case 0x00:
8417: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
8418: break;
8419: default:
8420: 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));
8421: m_CF = 1;
8422: break;
8423: }
8424: }
8425:
1.1.1.37 root 8426: UINT16 pcbios_printer_jis2sjis(UINT16 jis)
8427: {
8428: UINT8 hi = jis >> 8;
8429: UINT8 lo = jis & 0xff;
8430:
8431: lo = (hi & 0x01) ? lo - 0x1f : lo + 0x7d;
8432: hi = (hi - 0x21) / 2 + 0x81;
8433: hi = (hi >= 0xa0) ? hi + 0x40 : hi;
8434: lo = (lo >= 0x7f) ? lo + 0x01 : lo;
8435:
8436: return((hi << 8) + lo);
8437: }
8438:
8439: UINT16 pcbios_printer_sjis2jis(UINT16 sjis)
8440: {
8441: UINT8 hi = sjis >> 8;
8442: UINT8 lo = sjis & 0xff;
8443:
8444: if(hi == 0x80 || (hi >= 0xeb && hi <= 0xef) || (hi >= 0xf4 && hi <= 0xff)) {
8445: return(0x2121);
8446: }
8447: if((lo >= 0x00 && lo <= 0x3f) || lo == 0x7f || (lo >= 0xfd && lo <= 0xff)) {
8448: return(0x2121);
8449: }
8450: if(hi >= 0xf0 && hi <= 0xf3) {
8451: // gaiji
8452: if(lo >= 0x40 && lo <= 0x7e) {
8453: return(0x7721 + lo - 0x40 + (hi - 0xf0) * 0x200);
8454: }
8455: if(lo >= 0x80 && lo <= 0x9e) {
8456: return(0x7760 + lo - 0x80 + (hi - 0xf0) * 0x200);
8457: }
8458: if(lo >= 0x9f && lo <= 0xfc) {
8459: return(0x7821 + lo - 0x9f + (hi - 0xf0) * 0x200);
8460: }
8461: }
8462: hi = (hi >= 0xe0) ? hi - 0x40 : hi;
8463: lo = (lo >= 0x80) ? lo - 0x01 : lo;
8464: hi = ((lo >= 0x9e) ? 1 : 0) + (hi - 0x81) * 2 + 0x21;
8465: lo = ((lo >= 0x9e) ? lo - 0x9e : lo - 0x40) + 0x21;
8466:
8467: return((hi << 8) + lo);
8468: }
8469:
1.1.1.38 root 8470: // AX�e�N�j�J�����t�@�����X�K�C�h 1989
8471: // �t�^10 ���{��g��PRINTER DRIVER NIOS�T�d�l
8472: // 6. �R���g���[���R�[�h�̉��
1.1.1.37 root 8473:
8474: void pcbios_printer_out(int c, UINT8 data)
8475: {
8476: if(pio[c].conv_mode) {
8477: if(pio[c].sjis_hi != 0) {
8478: if(!pio[c].jis_mode) {
8479: printer_out(c, 0x1c);
8480: printer_out(c, 0x26);
8481: pio[c].jis_mode = true;
8482: }
8483: UINT16 jis = pcbios_printer_sjis2jis((pio[c].sjis_hi << 8) | data);
8484: printer_out(c, jis >> 8);
8485: printer_out(c, jis & 0xff);
8486: pio[c].sjis_hi = 0;
8487: } else if(pio[c].esc_buf[0] == 0x1b) {
8488: printer_out(c, data);
8489: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
8490: pio[c].esc_buf[pio[c].esc_len] = data;
8491: }
8492: pio[c].esc_len++;
8493:
8494: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 8495: case 0x33: // 1Bh 33h XX
8496: case 0x4a: // 1Bh 4Ah XX
8497: case 0x4e: // 1Bh 4Eh XX
8498: case 0x51: // 1Bh 51h XX
8499: case 0x55: // 1Bh 55h XX
8500: case 0x6c: // 1Bh 6Ch XX
8501: case 0x71: // 1Bh 71h XX
8502: case 0x72: // 1Bh 72h XX
1.1.1.37 root 8503: if(pio[c].esc_len == 3) {
8504: pio[c].esc_buf[0] = 0x00;
8505: }
8506: break;
1.1.1.38 root 8507: case 0x24: // 1Bh 24h XX XX
8508: case 0x5c: // 1Bh 5Ch XX XX
1.1.1.37 root 8509: if(pio[c].esc_len == 4) {
8510: pio[c].esc_buf[0] = 0x00;
8511: }
8512: break;
1.1.1.38 root 8513: case 0x2a: // 1Bh 2Ah XX XX XX data
1.1.1.37 root 8514: if(pio[c].esc_len >= 3) {
8515: switch(pio[c].esc_buf[2]) {
8516: case 0: case 1: case 2: case 3: case 4: case 6:
8517: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 1) {
8518: pio[c].esc_buf[0] = 0x00;
8519: }
8520: break;
8521: case 32: case 33: case 38: case 39: case 40:
8522: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 3) {
8523: pio[c].esc_buf[0] = 0x00;
8524: }
8525: break;
1.1.1.38 root 8526: case 71: case 72: case 73:
8527: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 6) {
8528: pio[c].esc_buf[0] = 0x00;
8529: }
8530: break;
1.1.1.37 root 8531: default:
8532: pio[c].esc_buf[0] = 0x00;
8533: break;
8534: }
8535: }
8536: break;
1.1.1.38 root 8537: case 0x40: // 1Bh 40h
1.1.1.37 root 8538: if(pio[c].jis_mode) {
8539: printer_out(c, 0x1c);
8540: printer_out(c, 0x2e);
8541: pio[c].jis_mode = false;
8542: }
8543: pio[c].esc_buf[0] = 0x00;
8544: break;
1.1.1.38 root 8545: case 0x42: // 1Bh 42h data 00h
8546: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8547: if(pio[c].esc_len >= 3 && data == 0) {
8548: pio[c].esc_buf[0] = 0x00;
8549: }
8550: break;
1.1.1.38 root 8551: case 0x43: // 1Bh 43h (00h) XX
1.1.1.37 root 8552: if(pio[c].esc_len >= 3 && data != 0) {
8553: pio[c].esc_buf[0] = 0x00;
8554: }
8555: break;
1.1.1.38 root 8556: default: // 1Bh XX
1.1.1.37 root 8557: pio[c].esc_buf[0] = 0x00;
8558: break;
8559: }
8560: } else if(pio[c].esc_buf[0] == 0x1c) {
8561: printer_out(c, data);
8562: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
8563: pio[c].esc_buf[pio[c].esc_len] = data;
8564: }
8565: pio[c].esc_len++;
8566:
8567: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 8568: case 0x21: // 1Ch 21h XX
8569: case 0x2d: // 1Ch 2Dh XX
8570: case 0x57: // 1Ch 57h XX
8571: case 0x6b: // 1Ch 6Bh XX
8572: case 0x72: // 1Ch 72h XX
8573: case 0x78: // 1Ch 78h XX
1.1.1.37 root 8574: if(pio[c].esc_len == 3) {
8575: pio[c].esc_buf[0] = 0x00;
8576: }
8577: break;
1.1.1.38 root 8578: case 0x26: // 1Ch 26h
1.1.1.37 root 8579: pio[c].jis_mode = true;
8580: pio[c].esc_buf[0] = 0x00;
8581: break;
1.1.1.38 root 8582: case 0x2e: // 1Ch 2Eh
1.1.1.37 root 8583: pio[c].jis_mode = false;
8584: pio[c].esc_buf[0] = 0x00;
8585: break;
1.1.1.38 root 8586: case 0x32: // 1Ch 32h XX XX data
1.1.1.37 root 8587: if(pio[c].esc_len == 76) {
8588: pio[c].esc_buf[0] = 0x00;
8589: }
8590: break;
1.1.1.38 root 8591: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8592: if(pio[c].esc_len == 6) {
8593: pio[c].esc_buf[0] = 0x00;
8594: }
8595: break;
1.1.1.38 root 8596: case 0x53: // 1Ch 53h XX XX
8597: case 0x54: // 1Ch 54h XX XX
1.1.1.37 root 8598: if(pio[c].esc_len == 4) {
8599: pio[c].esc_buf[0] = 0x00;
8600: }
8601: break;
1.1.1.38 root 8602: default: // 1Ch XX
1.1.1.37 root 8603: pio[c].esc_buf[0] = 0x00;
8604: break;
8605: }
8606: } else if(data == 0x1b || data == 0x1c) {
8607: printer_out(c, data);
8608: pio[c].esc_buf[0] = data;
8609: pio[c].esc_len = 1;
8610: } else if((data >= 0x80 && data <= 0x9f) || (data >= 0xe0 && data <= 0xff)) {
8611: pio[c].sjis_hi = data;
8612: } else {
8613: if(pio[c].jis_mode) {
8614: printer_out(c, 0x1c);
8615: printer_out(c, 0x2e);
8616: pio[c].jis_mode = false;
8617: }
8618: printer_out(c, data);
8619: }
8620: } else {
8621: if(pio[c].jis_mode) {
8622: printer_out(c, 0x1c);
8623: printer_out(c, 0x2e);
8624: pio[c].jis_mode = false;
8625: }
8626: printer_out(c, data);
8627: }
8628: }
8629:
8630: inline void pcbios_int_17h_00h()
8631: {
8632: if(REG16(DX) < 3) {
8633: pcbios_printer_out(REG16(DX), REG8(AL));
8634: REG8(AH) = 0xd0;
8635: }
8636: }
8637:
8638: inline void pcbios_int_17h_01h()
8639: {
8640: if(REG16(DX) < 3) {
8641: REG8(AH) = 0xd0;
8642: }
8643: }
8644:
8645: inline void pcbios_int_17h_02h()
8646: {
8647: if(REG16(DX) < 3) {
8648: REG8(AH) = 0xd0;
8649: }
8650: }
8651:
8652: inline void pcbios_int_17h_03h()
8653: {
8654: switch(REG8(AL)) {
8655: case 0x00:
8656: if(REG16(DX) < 3) {
8657: if(pio[REG16(DX)].jis_mode) {
8658: printer_out(REG16(DX), 0x1c);
8659: printer_out(REG16(DX), 0x2e);
8660: pio[REG16(DX)].jis_mode = false;
8661: }
8662: for(UINT16 i = 0; i < REG16(CX); i++) {
8663: printer_out(REG16(DX), mem[SREG_BASE(ES) + REG16(BX) + i]);
8664: }
8665: REG16(CX) = 0x0000;
8666: REG8(AH) = 0xd0;
8667: }
8668: break;
8669: default:
8670: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x17, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8671: break;
8672: }
8673: }
8674:
8675: inline void pcbios_int_17h_50h()
8676: {
8677: switch(REG8(AL)) {
8678: case 0x00:
8679: if(REG16(DX) < 3) {
8680: if(REG16(BX) = 0x0001) {
8681: pio[REG16(DX)].conv_mode = false;
8682: REG8(AL) = 0x00;
8683: } else if(REG16(BX) = 0x0051) {
8684: pio[REG16(DX)].conv_mode = true;
8685: REG8(AL) = 0x00;
8686: } else {
8687: REG8(AL) = 0x01;
8688: }
8689: } else {
8690: REG8(AL) = 0x02;
8691: }
8692: break;
8693: case 0x01:
8694: if(REG16(DX) < 3) {
8695: if(pio[REG16(DX)].conv_mode) {
8696: REG16(BX) = 0x0051;
8697: } else {
8698: REG16(BX) = 0x0001;
8699: }
8700: REG8(AL) = 0x00;
8701: } else {
8702: REG8(AL) = 0x02;
8703: }
8704: break;
8705: default:
8706: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x17, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8707: break;
8708: }
8709: }
8710:
8711: inline void pcbios_int_17h_51h()
8712: {
8713: if(REG8(DH) >= 0x21 && REG8(DH) <= 0x7e && REG8(DL) >= 0x21 && REG8(DL) <= 0x7e) {
8714: REG16(DX) = pcbios_printer_jis2sjis(REG16(DX));
8715: } else {
8716: REG16(DX) = 0x0000;
8717: }
8718: }
8719:
8720: inline void pcbios_int_17h_52h()
8721: {
8722: if(((REG8(DH) >= 0x81 && REG8(DH) <= 0x9f) || (REG8(DH) >= 0xe0 && REG8(DH) <= 0xfc)) && (REG8(DL) >= 0x40 && REG8(DL) <= 0xfc && REG8(DL) != 0x7f)) {
8723: REG16(DX) = pcbios_printer_sjis2jis(REG16(DX));
8724: } else {
8725: REG16(DX) = 0x0000;
8726: }
8727: }
8728:
8729: inline void pcbios_int_17h_84h()
8730: {
8731: if(REG16(DX) < 3) {
8732: if(pio[REG16(DX)].jis_mode) {
8733: printer_out(REG16(DX), 0x1c);
8734: printer_out(REG16(DX), 0x2e);
8735: pio[REG16(DX)].jis_mode = false;
8736: }
8737: printer_out(REG16(DX), REG8(AL));
8738: REG8(AH) = 0xd0;
8739: }
8740: }
8741:
8742: inline void pcbios_int_17h_85h()
8743: {
8744: pio[0].conv_mode = (REG8(AL) == 0x00);
8745: }
8746:
1.1 root 8747: inline void pcbios_int_1ah_00h()
8748: {
1.1.1.19 root 8749: pcbios_update_daily_timer_counter(timeGetTime());
8750: REG16(CX) = *(UINT16 *)(mem + 0x46e);
8751: REG16(DX) = *(UINT16 *)(mem + 0x46c);
8752: REG8(AL) = mem[0x470];
8753: mem[0x470] = 0;
1.1 root 8754: }
8755:
8756: inline int to_bcd(int t)
8757: {
8758: int u = (t % 100) / 10;
8759: return (u << 4) | (t % 10);
8760: }
8761:
8762: inline void pcbios_int_1ah_02h()
8763: {
8764: SYSTEMTIME time;
8765:
8766: GetLocalTime(&time);
8767: REG8(CH) = to_bcd(time.wHour);
8768: REG8(CL) = to_bcd(time.wMinute);
8769: REG8(DH) = to_bcd(time.wSecond);
8770: REG8(DL) = 0x00;
8771: }
8772:
8773: inline void pcbios_int_1ah_04h()
8774: {
8775: SYSTEMTIME time;
8776:
8777: GetLocalTime(&time);
8778: REG8(CH) = to_bcd(time.wYear / 100);
8779: REG8(CL) = to_bcd(time.wYear);
8780: REG8(DH) = to_bcd(time.wMonth);
8781: REG8(DL) = to_bcd(time.wDay);
8782: }
8783:
8784: inline void pcbios_int_1ah_0ah()
8785: {
8786: SYSTEMTIME time;
8787: FILETIME file_time;
8788: WORD dos_date, dos_time;
8789:
8790: GetLocalTime(&time);
8791: SystemTimeToFileTime(&time, &file_time);
8792: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
8793: REG16(CX) = dos_date;
8794: }
8795:
8796: // msdos system call
8797:
1.1.1.43 root 8798: inline void msdos_int_21h_56h(int lfn);
8799:
1.1 root 8800: inline void msdos_int_21h_00h()
8801: {
1.1.1.3 root 8802: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 8803: }
8804:
1.1.1.35 root 8805: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID)
1.1 root 8806: {
8807: REG8(AL) = msdos_getche();
1.1.1.33 root 8808: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8809:
1.1.1.35 root 8810: #ifdef USE_SERVICE_THREAD
8811: service_exit = true;
8812: #endif
8813: return(0);
8814: }
8815:
8816: inline void msdos_int_21h_01h()
8817: {
8818: #ifdef USE_SERVICE_THREAD
8819: start_service_loop(msdos_int_21h_01h_thread);
8820: #else
8821: msdos_int_21h_01h_thread(NULL);
8822: REQUEST_HARDWRE_UPDATE();
8823: #endif
1.1 root 8824: }
8825:
8826: inline void msdos_int_21h_02h()
8827: {
1.1.1.33 root 8828: UINT8 data = REG8(DL);
8829: msdos_putch(data);
8830: REG8(AL) = data;
8831: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8832: }
8833:
8834: inline void msdos_int_21h_03h()
8835: {
8836: REG8(AL) = msdos_aux_in();
8837: }
8838:
8839: inline void msdos_int_21h_04h()
8840: {
8841: msdos_aux_out(REG8(DL));
8842: }
8843:
8844: inline void msdos_int_21h_05h()
8845: {
8846: msdos_prn_out(REG8(DL));
8847: }
8848:
8849: inline void msdos_int_21h_06h()
8850: {
8851: if(REG8(DL) == 0xff) {
8852: if(msdos_kbhit()) {
8853: REG8(AL) = msdos_getch();
1.1.1.3 root 8854: #if defined(HAS_I386)
8855: m_ZF = 0;
8856: #else
8857: m_ZeroVal = 1;
8858: #endif
1.1 root 8859: } else {
8860: REG8(AL) = 0;
1.1.1.3 root 8861: #if defined(HAS_I386)
8862: m_ZF = 1;
8863: #else
8864: m_ZeroVal = 0;
8865: #endif
1.1.1.14 root 8866: maybe_idle();
1.1 root 8867: }
8868: } else {
1.1.1.33 root 8869: UINT8 data = REG8(DL);
8870: msdos_putch(data);
8871: REG8(AL) = data;
1.1 root 8872: }
8873: }
8874:
1.1.1.35 root 8875: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID)
1.1 root 8876: {
8877: REG8(AL) = msdos_getch();
1.1.1.26 root 8878:
1.1.1.35 root 8879: #ifdef USE_SERVICE_THREAD
8880: service_exit = true;
8881: #endif
8882: return(0);
1.1 root 8883: }
8884:
1.1.1.35 root 8885: inline void msdos_int_21h_07h()
8886: {
8887: #ifdef USE_SERVICE_THREAD
8888: start_service_loop(msdos_int_21h_07h_thread);
8889: #else
8890: msdos_int_21h_07h_thread(NULL);
8891: REQUEST_HARDWRE_UPDATE();
8892: #endif
8893: }
8894:
8895: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID)
1.1 root 8896: {
8897: REG8(AL) = msdos_getch();
1.1.1.33 root 8898: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8899:
1.1.1.35 root 8900: #ifdef USE_SERVICE_THREAD
8901: service_exit = true;
8902: #endif
8903: return(0);
8904: }
8905:
8906: inline void msdos_int_21h_08h()
8907: {
8908: #ifdef USE_SERVICE_THREAD
8909: start_service_loop(msdos_int_21h_08h_thread);
8910: #else
8911: msdos_int_21h_08h_thread(NULL);
8912: REQUEST_HARDWRE_UPDATE();
8913: #endif
1.1 root 8914: }
8915:
8916: inline void msdos_int_21h_09h()
8917: {
1.1.1.21 root 8918: msdos_stdio_reopen();
8919:
1.1.1.20 root 8920: process_t *process = msdos_process_info_get(current_psp);
8921: int fd = msdos_psp_get_file_table(1, current_psp);
8922:
1.1.1.14 root 8923: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
8924: int len = 0;
1.1 root 8925:
1.1.1.14 root 8926: while(str[len] != '$' && len < 0x10000) {
8927: len++;
8928: }
1.1.1.20 root 8929: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 8930: // stdout is redirected to file
1.1.1.20 root 8931: msdos_write(fd, str, len);
1.1 root 8932: } else {
8933: for(int i = 0; i < len; i++) {
1.1.1.14 root 8934: msdos_putch(str[i]);
1.1 root 8935: }
8936: }
1.1.1.33 root 8937: REG8(AL) = '$';
8938: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8939: }
8940:
1.1.1.35 root 8941: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID)
1.1 root 8942: {
1.1.1.3 root 8943: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 8944: int max = mem[ofs] - 1;
8945: UINT8 *buf = mem + ofs + 2;
8946: int chr, p = 0;
8947:
8948: while((chr = msdos_getch()) != 0x0d) {
1.1.1.33 root 8949: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 8950: p = 0;
1.1.1.33 root 8951: msdos_putch(0x03);
8952: msdos_putch(0x0d);
8953: msdos_putch(0x0a);
1.1.1.26 root 8954: break;
1.1.1.33 root 8955: } else if(ctrl_break_pressed) {
8956: // skip this byte
1.1.1.26 root 8957: } else if(chr == 0x00) {
1.1 root 8958: // skip 2nd byte
8959: msdos_getch();
8960: } else if(chr == 0x08) {
8961: // back space
8962: if(p > 0) {
8963: p--;
1.1.1.20 root 8964: if(msdos_ctrl_code_check(buf[p])) {
1.1.1.34 root 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.36 root 8971: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
8972: p--;
8973: msdos_putch(0x08);
8974: msdos_putch(0x08);
8975: msdos_putch(0x20);
8976: msdos_putch(0x20);
8977: msdos_putch(0x08);
8978: msdos_putch(0x08);
1.1.1.34 root 8979: } else {
8980: msdos_putch(0x08);
8981: msdos_putch(0x20);
8982: msdos_putch(0x08);
8983: }
8984: }
8985: } else if(chr == 0x1b) {
8986: // escape
8987: while(p > 0) {
8988: p--;
8989: if(msdos_ctrl_code_check(buf[p])) {
8990: msdos_putch(0x08);
8991: msdos_putch(0x08);
8992: msdos_putch(0x20);
8993: msdos_putch(0x20);
8994: msdos_putch(0x08);
8995: msdos_putch(0x08);
1.1.1.20 root 8996: } else {
1.1.1.34 root 8997: msdos_putch(0x08);
8998: msdos_putch(0x20);
8999: msdos_putch(0x08);
1.1.1.20 root 9000: }
1.1 root 9001: }
9002: } else if(p < max) {
9003: buf[p++] = chr;
9004: msdos_putch(chr);
9005: }
9006: }
9007: buf[p] = 0x0d;
9008: mem[ofs + 1] = p;
1.1.1.33 root 9009: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 9010:
1.1.1.35 root 9011: #ifdef USE_SERVICE_THREAD
9012: service_exit = true;
9013: #endif
9014: return(0);
9015: }
9016:
9017: inline void msdos_int_21h_0ah()
9018: {
9019: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) {
9020: #ifdef USE_SERVICE_THREAD
9021: start_service_loop(msdos_int_21h_0ah_thread);
9022: #else
9023: msdos_int_21h_0ah_thread(NULL);
9024: REQUEST_HARDWRE_UPDATE();
9025: #endif
9026: }
1.1 root 9027: }
9028:
9029: inline void msdos_int_21h_0bh()
9030: {
9031: if(msdos_kbhit()) {
9032: REG8(AL) = 0xff;
9033: } else {
9034: REG8(AL) = 0x00;
1.1.1.14 root 9035: maybe_idle();
1.1 root 9036: }
1.1.1.33 root 9037: ctrl_break_detected = ctrl_break_pressed;
1.1 root 9038: }
9039:
9040: inline void msdos_int_21h_0ch()
9041: {
9042: // clear key buffer
1.1.1.21 root 9043: msdos_stdio_reopen();
9044:
1.1.1.20 root 9045: process_t *process = msdos_process_info_get(current_psp);
9046: int fd = msdos_psp_get_file_table(0, current_psp);
9047:
9048: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 9049: // stdin is redirected to file
9050: } else {
9051: while(msdos_kbhit()) {
9052: msdos_getch();
9053: }
9054: }
9055:
9056: switch(REG8(AL)) {
9057: case 0x01:
9058: msdos_int_21h_01h();
9059: break;
9060: case 0x06:
9061: msdos_int_21h_06h();
9062: break;
9063: case 0x07:
9064: msdos_int_21h_07h();
9065: break;
9066: case 0x08:
9067: msdos_int_21h_08h();
9068: break;
9069: case 0x0a:
9070: msdos_int_21h_0ah();
9071: break;
9072: default:
1.1.1.48 root 9073: // the buffer is flushed but no input is attempted
1.1 root 9074: break;
9075: }
9076: }
9077:
9078: inline void msdos_int_21h_0dh()
9079: {
9080: }
9081:
9082: inline void msdos_int_21h_0eh()
9083: {
9084: if(REG8(DL) < 26) {
9085: _chdrive(REG8(DL) + 1);
9086: msdos_cds_update(REG8(DL));
1.1.1.23 root 9087: msdos_sda_update(current_psp);
1.1 root 9088: }
9089: REG8(AL) = 26; // zdrive
9090: }
9091:
1.1.1.14 root 9092: inline void msdos_int_21h_0fh()
9093: {
9094: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9095: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.45 root 9096: const char *path = msdos_fcb_path(fcb);
1.1.1.14 root 9097: 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 9098:
1.1.1.14 root 9099: if(hFile == INVALID_HANDLE_VALUE) {
9100: REG8(AL) = 0xff;
9101: } else {
9102: REG8(AL) = 0;
9103: fcb->current_block = 0;
9104: fcb->record_size = 128;
9105: fcb->file_size = GetFileSize(hFile, NULL);
9106: fcb->handle = hFile;
9107: fcb->cur_record = 0;
9108: }
9109: }
9110:
9111: inline void msdos_int_21h_10h()
9112: {
9113: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9114: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9115:
9116: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
9117: }
9118:
1.1 root 9119: inline void msdos_int_21h_11h()
9120: {
1.1.1.3 root 9121: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9122: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9123:
9124: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9125: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9126: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
9127: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1.1.45 root 9128: const char *path = msdos_fcb_path(fcb);
1.1 root 9129: WIN32_FIND_DATA fd;
9130:
1.1.1.13 root 9131: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
9132: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9133: FindClose(dtainfo->find_handle);
9134: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9135: }
9136: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 9137: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
9138: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 9139:
1.1.1.14 root 9140: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
9141: dtainfo->allowable_mask &= ~8;
1.1 root 9142: }
1.1.1.14 root 9143: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
9144: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9145: !msdos_find_file_has_8dot3name(&fd)) {
9146: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9147: FindClose(dtainfo->find_handle);
9148: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9149: break;
9150: }
9151: }
9152: }
1.1.1.13 root 9153: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9154: if(ext_fcb->flag == 0xff) {
9155: ext_find->flag = 0xff;
9156: memset(ext_find->reserved, 0, 5);
9157: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9158: }
9159: find->drive = _getdrive();
1.1.1.13 root 9160: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 9161: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9162: find->nt_res = 0;
9163: msdos_find_file_conv_local_time(&fd);
9164: find->create_time_ms = 0;
9165: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9166: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9167: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9168: find->cluster_hi = find->cluster_lo = 0;
9169: find->file_size = fd.nFileSizeLow;
9170: REG8(AL) = 0x00;
1.1.1.14 root 9171: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9172: if(ext_fcb->flag == 0xff) {
9173: ext_find->flag = 0xff;
9174: memset(ext_find->reserved, 0, 5);
9175: ext_find->attribute = 8;
9176: }
9177: find->drive = _getdrive();
9178: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
9179: find->attribute = 8;
9180: find->nt_res = 0;
9181: msdos_find_file_conv_local_time(&fd);
9182: find->create_time_ms = 0;
9183: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9184: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9185: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9186: find->cluster_hi = find->cluster_lo = 0;
9187: find->file_size = 0;
1.1.1.14 root 9188: dtainfo->allowable_mask &= ~8;
1.1 root 9189: REG8(AL) = 0x00;
9190: } else {
9191: REG8(AL) = 0xff;
9192: }
9193: }
9194:
9195: inline void msdos_int_21h_12h()
9196: {
1.1.1.3 root 9197: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 9198: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9199:
9200: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9201: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9202: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
9203: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9204: WIN32_FIND_DATA fd;
9205:
1.1.1.13 root 9206: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
9207: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9208: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 9209: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9210: !msdos_find_file_has_8dot3name(&fd)) {
9211: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9212: FindClose(dtainfo->find_handle);
9213: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9214: break;
9215: }
9216: }
9217: } else {
1.1.1.13 root 9218: FindClose(dtainfo->find_handle);
9219: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9220: }
9221: }
1.1.1.13 root 9222: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9223: if(ext_fcb->flag == 0xff) {
9224: ext_find->flag = 0xff;
9225: memset(ext_find->reserved, 0, 5);
9226: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9227: }
9228: find->drive = _getdrive();
1.1.1.13 root 9229: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 9230: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9231: find->nt_res = 0;
9232: msdos_find_file_conv_local_time(&fd);
9233: find->create_time_ms = 0;
9234: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9235: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9236: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9237: find->cluster_hi = find->cluster_lo = 0;
9238: find->file_size = fd.nFileSizeLow;
9239: REG8(AL) = 0x00;
1.1.1.14 root 9240: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9241: if(ext_fcb->flag == 0xff) {
9242: ext_find->flag = 0xff;
9243: memset(ext_find->reserved, 0, 5);
9244: ext_find->attribute = 8;
9245: }
9246: find->drive = _getdrive();
9247: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
9248: find->attribute = 8;
9249: find->nt_res = 0;
9250: msdos_find_file_conv_local_time(&fd);
9251: find->create_time_ms = 0;
9252: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9253: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9254: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9255: find->cluster_hi = find->cluster_lo = 0;
9256: find->file_size = 0;
1.1.1.14 root 9257: dtainfo->allowable_mask &= ~8;
1.1 root 9258: REG8(AL) = 0x00;
9259: } else {
9260: REG8(AL) = 0xff;
9261: }
9262: }
9263:
9264: inline void msdos_int_21h_13h()
9265: {
1.1.1.3 root 9266: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 9267: REG8(AL) = 0xff;
9268: } else {
9269: REG8(AL) = 0x00;
9270: }
9271: }
9272:
1.1.1.16 root 9273: inline void msdos_int_21h_14h()
9274: {
9275: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9276: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9277: process_t *process = msdos_process_info_get(current_psp);
9278: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9279: DWORD num = 0;
9280:
9281: memset(mem + dta_laddr, 0, fcb->record_size);
9282: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9283: REG8(AL) = 1;
9284: } else {
9285: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
9286: fcb->current_block = (position & 0xffffff) / fcb->record_size;
9287: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
9288: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
9289: }
9290: }
9291:
9292: inline void msdos_int_21h_15h()
1.1.1.14 root 9293: {
9294: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9295: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 9296: process_t *process = msdos_process_info_get(current_psp);
9297: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9298: DWORD num = 0;
1.1.1.14 root 9299:
1.1.1.16 root 9300: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9301: REG8(AL) = 1;
9302: } else {
9303: fcb->file_size = GetFileSize(fcb->handle, NULL);
9304: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
9305: fcb->current_block = (position & 0xffffff) / fcb->record_size;
9306: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
9307: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
9308: }
9309: }
9310:
9311: inline void msdos_int_21h_16h()
9312: {
9313: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9314: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.45 root 9315: const char *path = msdos_fcb_path(fcb);
1.1.1.14 root 9316: 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 9317:
1.1.1.14 root 9318: if(hFile == INVALID_HANDLE_VALUE) {
9319: REG8(AL) = 0xff;
9320: } else {
9321: REG8(AL) = 0;
9322: fcb->current_block = 0;
9323: fcb->record_size = 128;
9324: fcb->file_size = 0;
9325: fcb->handle = hFile;
9326: fcb->cur_record = 0;
9327: }
9328: }
9329:
1.1.1.16 root 9330: inline void msdos_int_21h_17h()
9331: {
9332: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9333: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
1.1.1.45 root 9334: // const char *path_src = msdos_fcb_path(fcb_src);
9335: char path_src[MAX_PATH];
9336: strcpy(path_src, msdos_fcb_path(fcb_src));
9337:
1.1.1.16 root 9338: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
9339: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
1.1.1.45 root 9340: // const char *path_dst = msdos_fcb_path(fcb_dst);
9341: char path_dst[MAX_PATH];
9342: strcpy(path_dst, msdos_fcb_path(fcb_dst));
1.1.1.16 root 9343:
9344: if(rename(path_src, path_dst)) {
9345: REG8(AL) = 0xff;
9346: } else {
9347: REG8(AL) = 0;
9348: }
9349: }
9350:
1.1 root 9351: inline void msdos_int_21h_18h()
9352: {
9353: REG8(AL) = 0x00;
9354: }
9355:
9356: inline void msdos_int_21h_19h()
9357: {
9358: REG8(AL) = _getdrive() - 1;
9359: }
9360:
9361: inline void msdos_int_21h_1ah()
9362: {
9363: process_t *process = msdos_process_info_get(current_psp);
9364:
9365: process->dta.w.l = REG16(DX);
1.1.1.3 root 9366: process->dta.w.h = SREG(DS);
1.1.1.23 root 9367: msdos_sda_update(current_psp);
1.1 root 9368: }
9369:
9370: inline void msdos_int_21h_1bh()
9371: {
9372: int drive_num = _getdrive() - 1;
9373: UINT16 seg, ofs;
9374:
9375: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9376: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9377: REG8(AL) = dpb->highest_sector_num + 1;
9378: REG16(CX) = dpb->bytes_per_sector;
9379: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 9380: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 9381: } else {
9382: REG8(AL) = 0xff;
1.1.1.3 root 9383: m_CF = 1;
1.1 root 9384: }
9385:
9386: }
9387:
9388: inline void msdos_int_21h_1ch()
9389: {
1.1.1.41 root 9390: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
1.1 root 9391: UINT16 seg, ofs;
9392:
9393: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9394: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9395: REG8(AL) = dpb->highest_sector_num + 1;
9396: REG16(CX) = dpb->bytes_per_sector;
9397: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 9398: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 9399: } else {
9400: REG8(AL) = 0xff;
1.1.1.3 root 9401: m_CF = 1;
1.1 root 9402: }
9403:
9404: }
9405:
9406: inline void msdos_int_21h_1dh()
9407: {
9408: REG8(AL) = 0;
9409: }
9410:
9411: inline void msdos_int_21h_1eh()
9412: {
9413: REG8(AL) = 0;
9414: }
9415:
9416: inline void msdos_int_21h_1fh()
9417: {
9418: int drive_num = _getdrive() - 1;
9419: UINT16 seg, ofs;
9420:
9421: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9422: REG8(AL) = 0;
1.1.1.3 root 9423: SREG(DS) = seg;
9424: i386_load_segment_descriptor(DS);
1.1 root 9425: REG16(BX) = ofs;
9426: } else {
9427: REG8(AL) = 0xff;
1.1.1.3 root 9428: m_CF = 1;
1.1 root 9429: }
9430: }
9431:
9432: inline void msdos_int_21h_20h()
9433: {
9434: REG8(AL) = 0;
9435: }
9436:
1.1.1.14 root 9437: inline void msdos_int_21h_21h()
9438: {
9439: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9440: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9441:
9442: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9443: REG8(AL) = 1;
9444: } else {
9445: process_t *process = msdos_process_info_get(current_psp);
9446: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9447: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 9448: DWORD num = 0;
1.1.1.14 root 9449: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9450: REG8(AL) = 1;
9451: } else {
9452: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9453: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 9454: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 9455: }
9456: }
9457: }
9458:
9459: inline void msdos_int_21h_22h()
9460: {
9461: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9462: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9463:
9464: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9465: REG8(AL) = 0xff;
9466: } else {
9467: process_t *process = msdos_process_info_get(current_psp);
9468: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 9469: DWORD num = 0;
1.1.1.14 root 9470: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
9471: fcb->file_size = GetFileSize(fcb->handle, NULL);
9472: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9473: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 9474: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 9475: }
9476: }
9477:
1.1.1.16 root 9478: inline void msdos_int_21h_23h()
9479: {
9480: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9481: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.45 root 9482: const char *path = msdos_fcb_path(fcb);
1.1.1.16 root 9483: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9484:
9485: if(hFile == INVALID_HANDLE_VALUE) {
9486: REG8(AL) = 0xff;
9487: } else {
9488: UINT32 size = GetFileSize(hFile, NULL);
9489: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
9490: REG8(AL) = 0;
9491: }
9492: }
9493:
9494: inline void msdos_int_21h_24h()
9495: {
9496: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9497: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9498:
9499: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
9500: }
9501:
1.1 root 9502: inline void msdos_int_21h_25h()
9503: {
9504: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 9505: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 9506: }
9507:
9508: inline void msdos_int_21h_26h()
9509: {
9510: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
9511:
9512: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
1.1.1.48 root 9513: psp->first_mcb = REG16(DX) + (PSP_SIZE >> 4);
1.1 root 9514: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
9515: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
9516: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
9517: psp->parent_psp = 0;
9518: }
9519:
1.1.1.16 root 9520: inline void msdos_int_21h_27h()
9521: {
9522: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9523: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9524:
9525: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9526: REG8(AL) = 1;
9527: } else {
9528: process_t *process = msdos_process_info_get(current_psp);
9529: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9530: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
9531: DWORD num = 0;
9532: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
9533: REG8(AL) = 1;
9534: } else {
9535: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9536: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9537: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
9538: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9539: }
9540: }
9541: }
9542:
9543: inline void msdos_int_21h_28h()
9544: {
9545: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9546: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9547:
9548: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9549: REG8(AL) = 0xff;
9550: } else {
9551: process_t *process = msdos_process_info_get(current_psp);
9552: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9553: DWORD num = 0;
9554: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
9555: fcb->file_size = GetFileSize(fcb->handle, NULL);
9556: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9557: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9558: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
9559: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9560: }
9561: }
9562:
1.1 root 9563: inline void msdos_int_21h_29h()
9564: {
1.1.1.20 root 9565: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
9566: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 9567: UINT8 drv = 0;
9568: char sep_chars[] = ":.;,=+";
9569: char end_chars[] = "\\<>|/\"[]";
9570: char spc_chars[] = " \t";
9571:
1.1.1.20 root 9572: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
9573: buffer[1023] = 0;
9574: memset(name, 0x20, sizeof(name));
9575: memset(ext, 0x20, sizeof(ext));
9576:
1.1 root 9577: if(REG8(AL) & 1) {
1.1.1.20 root 9578: ofs += strspn((char *)(buffer + ofs), spc_chars);
9579: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 9580: ofs++;
9581: }
9582: }
1.1.1.20 root 9583: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 9584:
1.1.1.24 root 9585: if(buffer[ofs + 1] == ':') {
9586: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
9587: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 9588: ofs += 2;
1.1.1.24 root 9589: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9590: ofs++;
9591: }
9592: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
9593: drv = buffer[ofs] - 'A' + 1;
1.1 root 9594: ofs += 2;
1.1.1.24 root 9595: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9596: ofs++;
9597: }
1.1 root 9598: }
9599: }
1.1.1.20 root 9600: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9601: UINT8 c = buffer[ofs];
9602: if(is_kanji) {
9603: is_kanji = 0;
9604: } else if(msdos_lead_byte_check(c)) {
9605: is_kanji = 1;
9606: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9607: break;
9608: } else if(c >= 'a' && c <= 'z') {
9609: c -= 0x20;
9610: }
9611: ofs++;
9612: name[i] = c;
9613: }
1.1.1.20 root 9614: if(buffer[ofs] == '.') {
1.1 root 9615: ofs++;
1.1.1.20 root 9616: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9617: UINT8 c = buffer[ofs];
9618: if(is_kanji) {
9619: is_kanji = 0;
9620: } else if(msdos_lead_byte_check(c)) {
9621: is_kanji = 1;
9622: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9623: break;
9624: } else if(c >= 'a' && c <= 'z') {
9625: c -= 0x20;
9626: }
9627: ofs++;
9628: ext[i] = c;
9629: }
9630: }
1.1.1.20 root 9631: int si = REG16(SI) + ofs;
1.1.1.3 root 9632: int ds = SREG(DS);
1.1 root 9633: while(si > 0xffff) {
9634: si -= 0x10;
9635: ds++;
9636: }
9637: REG16(SI) = si;
1.1.1.3 root 9638: SREG(DS) = ds;
9639: i386_load_segment_descriptor(DS);
1.1 root 9640:
1.1.1.3 root 9641: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 9642: if(!(REG8(AL) & 2) || drv != 0) {
9643: fcb[0] = drv;
9644: }
9645: if(!(REG8(AL) & 4) || name[0] != 0x20) {
9646: memcpy(fcb + 1, name, 8);
9647: }
9648: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
9649: memcpy(fcb + 9, ext, 3);
9650: }
9651: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 9652: if(fcb[i] == '*') {
9653: found_star = 1;
9654: }
9655: if(found_star) {
9656: fcb[i] = '?';
9657: }
9658: }
1.1.1.20 root 9659: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 9660: if(fcb[i] == '*') {
9661: found_star = 1;
9662: }
9663: if(found_star) {
9664: fcb[i] = '?';
9665: }
9666: }
9667:
1.1.1.44 root 9668: if(drv == 0 || msdos_is_valid_drive(drv - 1)) {
1.1 root 9669: if(memchr(fcb + 1, '?', 8 + 3)) {
9670: REG8(AL) = 0x01;
1.1.1.20 root 9671: } else {
9672: REG8(AL) = 0x00;
1.1 root 9673: }
9674: } else {
9675: REG8(AL) = 0xff;
9676: }
9677: }
9678:
9679: inline void msdos_int_21h_2ah()
9680: {
9681: SYSTEMTIME sTime;
9682:
9683: GetLocalTime(&sTime);
9684: REG16(CX) = sTime.wYear;
9685: REG8(DH) = (UINT8)sTime.wMonth;
9686: REG8(DL) = (UINT8)sTime.wDay;
9687: REG8(AL) = (UINT8)sTime.wDayOfWeek;
9688: }
9689:
9690: inline void msdos_int_21h_2bh()
9691: {
1.1.1.14 root 9692: REG8(AL) = 0xff;
1.1 root 9693: }
9694:
9695: inline void msdos_int_21h_2ch()
9696: {
9697: SYSTEMTIME sTime;
9698:
9699: GetLocalTime(&sTime);
9700: REG8(CH) = (UINT8)sTime.wHour;
9701: REG8(CL) = (UINT8)sTime.wMinute;
9702: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 9703: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 9704: }
9705:
9706: inline void msdos_int_21h_2dh()
9707: {
9708: REG8(AL) = 0x00;
9709: }
9710:
9711: inline void msdos_int_21h_2eh()
9712: {
9713: process_t *process = msdos_process_info_get(current_psp);
9714:
9715: process->verify = REG8(AL);
9716: }
9717:
9718: inline void msdos_int_21h_2fh()
9719: {
9720: process_t *process = msdos_process_info_get(current_psp);
9721:
9722: REG16(BX) = process->dta.w.l;
1.1.1.3 root 9723: SREG(ES) = process->dta.w.h;
9724: i386_load_segment_descriptor(ES);
1.1 root 9725: }
9726:
9727: inline void msdos_int_21h_30h()
9728: {
9729: // Version Flag / OEM
1.1.1.27 root 9730: if(REG8(AL) == 0x01) {
1.1.1.29 root 9731: #ifdef SUPPORT_HMA
9732: REG16(BX) = 0x0000;
9733: #else
9734: REG16(BX) = 0x1000; // DOS is in HMA
9735: #endif
1.1 root 9736: } else {
1.1.1.27 root 9737: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
9738: // but this is not correct on Windows 98 SE
9739: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
9740: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 9741: }
1.1.1.27 root 9742: REG16(CX) = 0x0000;
1.1.1.30 root 9743: REG8(AL) = dos_major_version; // 7
9744: REG8(AH) = dos_minor_version; // 10
1.1 root 9745: }
9746:
9747: inline void msdos_int_21h_31h()
9748: {
1.1.1.29 root 9749: try {
9750: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9751: } catch(...) {
9752: // recover the broken mcb
9753: int mcb_seg = current_psp - 1;
9754: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 9755:
1.1.1.29 root 9756: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 9757: mcb->mz = 'M';
9758: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
9759:
1.1.1.29 root 9760: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 9761: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 9762: } else {
1.1.1.39 root 9763: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 9764: }
9765: } else {
9766: mcb->mz = 'Z';
1.1.1.30 root 9767: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 9768: }
9769: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9770: }
1.1 root 9771: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
9772: }
9773:
9774: inline void msdos_int_21h_32h()
9775: {
9776: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
9777: UINT16 seg, ofs;
9778:
9779: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9780: REG8(AL) = 0;
1.1.1.3 root 9781: SREG(DS) = seg;
9782: i386_load_segment_descriptor(DS);
1.1 root 9783: REG16(BX) = ofs;
9784: } else {
9785: REG8(AL) = 0xff;
1.1.1.3 root 9786: m_CF = 1;
1.1 root 9787: }
9788: }
9789:
9790: inline void msdos_int_21h_33h()
9791: {
9792: char path[MAX_PATH];
1.1.1.48 root 9793: char drive = 3; // C:
1.1 root 9794:
9795: switch(REG8(AL)) {
9796: case 0x00:
1.1.1.33 root 9797: REG8(DL) = ctrl_break_checking;
1.1 root 9798: break;
9799: case 0x01:
1.1.1.33 root 9800: ctrl_break_checking = REG8(DL);
9801: break;
9802: case 0x02:
9803: {
9804: UINT8 old = ctrl_break_checking;
9805: ctrl_break_checking = REG8(DL);
9806: REG8(DL) = old;
9807: }
9808: break;
9809: case 0x03:
9810: case 0x04:
9811: // DOS 4.0+ - Unused
1.1 root 9812: break;
9813: case 0x05:
1.1.1.48 root 9814: if(GetSystemDirectory(path, MAX_PATH) != 0) {
9815: if(path[0] >= 'a' && path[0] <= 'z') {
9816: drive = path[0] - 'a' + 1;
9817: } else if(path[0] >= 'A' && path[0] <= 'Z') {
9818: drive = path[0] - 'A' + 1;
9819: }
1.1 root 9820: }
1.1.1.48 root 9821: REG8(DL) = (UINT8)drive;
1.1 root 9822: break;
9823: case 0x06:
1.1.1.2 root 9824: // MS-DOS version (7.10)
1.1 root 9825: REG8(BL) = 7;
1.1.1.2 root 9826: REG8(BH) = 10;
1.1 root 9827: REG8(DL) = 0;
1.1.1.29 root 9828: #ifdef SUPPORT_HMA
9829: REG8(DH) = 0x00;
9830: #else
9831: REG8(DH) = 0x10; // DOS is in HMA
9832: #endif
1.1 root 9833: break;
1.1.1.6 root 9834: case 0x07:
9835: if(REG8(DL) == 0) {
9836: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
9837: } else if(REG8(DL) == 1) {
9838: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
9839: }
9840: break;
1.1 root 9841: default:
1.1.1.22 root 9842: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 9843: // REG16(AX) = 0x01;
9844: // m_CF = 1;
9845: REG8(AL) = 0xff;
1.1 root 9846: break;
9847: }
9848: }
9849:
1.1.1.23 root 9850: inline void msdos_int_21h_34h()
9851: {
9852: SREG(ES) = SDA_TOP >> 4;
9853: i386_load_segment_descriptor(ES);
9854: REG16(BX) = offsetof(sda_t, indos_flag);;
9855: }
9856:
1.1 root 9857: inline void msdos_int_21h_35h()
9858: {
9859: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 9860: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
9861: i386_load_segment_descriptor(ES);
1.1 root 9862: }
9863:
9864: inline void msdos_int_21h_36h()
9865: {
9866: struct _diskfree_t df = {0};
9867:
9868: if(_getdiskfree(REG8(DL), &df) == 0) {
9869: REG16(AX) = (UINT16)df.sectors_per_cluster;
9870: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 9871: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
9872: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 9873: } else {
9874: REG16(AX) = 0xffff;
9875: }
9876: }
9877:
9878: inline void msdos_int_21h_37h()
9879: {
1.1.1.22 root 9880: static UINT8 dev_flag = 0xff;
1.1 root 9881:
9882: switch(REG8(AL)) {
9883: case 0x00:
1.1.1.22 root 9884: {
9885: process_t *process = msdos_process_info_get(current_psp);
9886: REG8(AL) = 0x00;
9887: REG8(DL) = process->switchar;
9888: }
1.1 root 9889: break;
9890: case 0x01:
1.1.1.22 root 9891: {
9892: process_t *process = msdos_process_info_get(current_psp);
9893: REG8(AL) = 0x00;
9894: process->switchar = REG8(DL);
1.1.1.23 root 9895: msdos_sda_update(current_psp);
1.1.1.22 root 9896: }
9897: break;
9898: case 0x02:
9899: REG8(DL) = dev_flag;
9900: break;
9901: case 0x03:
9902: dev_flag = REG8(DL);
9903: break;
9904: case 0xd0:
9905: case 0xd1:
9906: case 0xd2:
9907: case 0xd3:
9908: case 0xd4:
9909: case 0xd5:
9910: case 0xd6:
9911: case 0xd7:
9912: case 0xdc:
9913: case 0xdd:
9914: case 0xde:
9915: case 0xdf:
1.1.1.48 root 9916: // DIET v1.43e
9917: // REG16(AX) = 1;
9918: REG8(AL) = 0xff;
1.1 root 9919: break;
9920: default:
1.1.1.22 root 9921: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 9922: // REG16(AX) = 1;
9923: REG8(AL) = 0xff;
1.1 root 9924: break;
9925: }
9926: }
9927:
1.1.1.42 root 9928: int get_country_info(country_info_t *ci, LCID locale)
1.1.1.17 root 9929: {
9930: char LCdata[80];
9931:
1.1.1.19 root 9932: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.42 root 9933: GetLocaleInfo(locale, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
1.1.1.17 root 9934: ci->currency_dec_digits = atoi(LCdata);
1.1.1.42 root 9935: GetLocaleInfo(locale, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
1.1.1.17 root 9936: ci->currency_format = *LCdata - '0';
1.1.1.42 root 9937: GetLocaleInfo(locale, LOCALE_IDATE, LCdata, sizeof(LCdata));
1.1.1.17 root 9938: ci->date_format = *LCdata - '0';
1.1.1.42 root 9939: GetLocaleInfo(locale, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
1.1.1.17 root 9940: memcpy(&ci->currency_symbol, LCdata, 4);
1.1.1.42 root 9941: GetLocaleInfo(locale, LOCALE_SDATE, LCdata, sizeof(LCdata));
1.1.1.17 root 9942: *ci->date_sep = *LCdata;
1.1.1.42 root 9943: GetLocaleInfo(locale, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
1.1.1.17 root 9944: *ci->dec_sep = *LCdata;
1.1.1.42 root 9945: GetLocaleInfo(locale, LOCALE_SLIST, LCdata, sizeof(LCdata));
1.1.1.17 root 9946: *ci->list_sep = *LCdata;
1.1.1.42 root 9947: GetLocaleInfo(locale, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
1.1.1.17 root 9948: *ci->thou_sep = *LCdata;
1.1.1.42 root 9949: GetLocaleInfo(locale, LOCALE_STIME, LCdata, sizeof(LCdata));
1.1.1.17 root 9950: *ci->time_sep = *LCdata;
1.1.1.42 root 9951: GetLocaleInfo(locale, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
1.1.1.17 root 9952: if(strchr(LCdata, 'H') != NULL) {
9953: ci->time_format = 1;
9954: }
1.1.1.49! root 9955: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffc:000a
! 9956: ci->case_map.w.h = DUMMY_TOP >> 4;
1.1.1.42 root 9957: GetLocaleInfo(locale, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
1.1.1.17 root 9958: return atoi(LCdata);
9959: }
9960:
1.1.1.42 root 9961: int get_country_info(country_info_t *ci, USHORT usPrimaryLanguage, USHORT usSubLanguage)
9962: {
9963: return get_country_info(ci, MAKELCID(MAKELANGID(usPrimaryLanguage, usSubLanguage), SORT_DEFAULT));
9964: }
9965:
9966: int get_country_info(country_info_t *ci)
9967: {
9968: return get_country_info(ci, LOCALE_USER_DEFAULT);
9969: }
9970:
1.1.1.43 root 9971: void set_country_info(country_info_t *ci, int size)
9972: {
9973: char LCdata[80];
9974:
9975: if(size >= 0x00 + 2) {
9976: memset(LCdata, 0, sizeof(LCdata));
9977: *LCdata = '0' + ci->date_format;
9978: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata);
9979: }
9980: if(size >= 0x02 + 5) {
9981: memset(LCdata, 0, sizeof(LCdata));
9982: memcpy(LCdata, &ci->currency_symbol, 4);
9983: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata);
9984: }
9985: if(size >= 0x07 + 2) {
9986: memset(LCdata, 0, sizeof(LCdata));
9987: *LCdata = *ci->thou_sep;
9988: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata);
9989: }
9990: if(size >= 0x09 + 2) {
9991: memset(LCdata, 0, sizeof(LCdata));
9992: *LCdata = *ci->dec_sep;
9993: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata);
9994: }
9995: if(size >= 0x0b + 2) {
9996: memset(LCdata, 0, sizeof(LCdata));
9997: *LCdata = *ci->date_sep;
9998: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata);
9999: }
10000: if(size >= 0x0d + 2) {
10001: memset(LCdata, 0, sizeof(LCdata));
10002: *LCdata = *ci->time_sep;
10003: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata);
10004: }
10005: if(size >= 0x0f + 1) {
10006: memset(LCdata, 0, sizeof(LCdata));
10007: *LCdata = '0' + ci->currency_format;
10008: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata);
10009: }
10010: if(size >= 0x10 + 1) {
10011: sprintf(LCdata, "%d", ci->currency_dec_digits);
10012: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata);
10013: }
10014: if(size >= 0x11 + 1) {
10015: // FIXME: is time format always H/h:mm:ss ???
10016: if(ci->time_format & 1) {
10017: sprintf(LCdata, "H%cmm%css", *ci->time_sep, *ci->time_sep);
10018: } else {
10019: sprintf(LCdata, "h%cmm%css", *ci->time_sep, *ci->time_sep);
10020: }
10021: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata);
10022: }
10023: if(size >= 0x12 + 4) {
10024: // 12h DWORD address of case map routine
10025: // (FAR CALL, AL = character to map to upper case [>= 80h])
10026: }
10027: if(size >= 0x16 + 2) {
10028: memset(LCdata, 0, sizeof(LCdata));
10029: *LCdata = *ci->list_sep;
10030: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata);
10031: }
10032: }
10033:
1.1.1.42 root 10034: #ifndef SUBLANG_SWAHILI
10035: #define SUBLANG_SWAHILI 0x01
10036: #endif
10037: #ifndef SUBLANG_TSWANA_BOTSWANA
10038: #define SUBLANG_TSWANA_BOTSWANA 0x02
10039: #endif
10040: #ifndef SUBLANG_LITHUANIAN_LITHUANIA
10041: #define SUBLANG_LITHUANIAN_LITHUANIA 0x01
10042: #endif
10043: #ifndef LANG_BANGLA
10044: #define LANG_BANGLA 0x45
10045: #endif
10046: #ifndef SUBLANG_BANGLA_BANGLADESH
10047: #define SUBLANG_BANGLA_BANGLADESH 0x02
10048: #endif
10049:
10050: static const struct {
10051: int code;
10052: USHORT usPrimaryLanguage;
10053: USHORT usSubLanguage;
10054: } country_table[] = {
10055: {0x001, LANG_ENGLISH, SUBLANG_ENGLISH_US}, // United States
10056: {0x002, LANG_FRENCH, SUBLANG_FRENCH_CANADIAN}, // Canadian-French
10057: {0x004, LANG_ENGLISH, SUBLANG_ENGLISH_CAN}, // Canada (English)
10058: {0x007, LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA}, // Russia
10059: {0x014, LANG_ARABIC, SUBLANG_ARABIC_EGYPT}, // Egypt
10060: {0x01B, LANG_ZULU, SUBLANG_ZULU_SOUTH_AFRICA}, // South Africa
10061: // {0x01B, LANG_XHOSA, SUBLANG_XHOSA_SOUTH_AFRICA}, // South Africa
10062: // {0x01B, LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA}, // South Africa
10063: // {0x01B, LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA}, // South Africa
10064: // {0x01B, LANG_SOTHO, SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA}, // South Africa
10065: // {0x01B, LANG_TSWANA, SUBLANG_TSWANA_SOUTH_AFRICA}, // South Africa
10066: {0x01E, LANG_GREEK, SUBLANG_GREEK_GREECE}, // Greece
10067: {0x01F, LANG_DUTCH, SUBLANG_DUTCH}, // Netherlands
10068: // {0x01F, LANG_FRISIAN, SUBLANG_FRISIAN_NETHERLANDS}, // Netherlands
10069: {0x020, LANG_DUTCH, SUBLANG_DUTCH_BELGIAN}, // Belgium
10070: // {0x020, LANG_FRENCH, SUBLANG_FRENCH_BELGIAN}, // Belgium
10071: {0x021, LANG_FRENCH, SUBLANG_FRENCH}, // France
10072: {0x022, LANG_SPANISH, SUBLANG_SPANISH}, // Spain
10073: {0x023, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria???
10074: {0x024, LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY}, // Hungary (not supported by DR DOS 5.0)
10075: {0x027, LANG_ITALIAN, SUBLANG_ITALIAN}, // Italy / San Marino / Vatican City
10076: {0x028, LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA}, // Romania
10077: {0x029, LANG_GERMAN, SUBLANG_GERMAN_SWISS}, // Switzerland / Liechtenstein
10078: // {0x029, LANG_FRENCH, SUBLANG_FRENCH_SWISS}, // Switzerland / Liechtenstein
10079: // {0x029, LANG_ITALIAN, SUBLANG_ITALIAN_SWISS}, // Switzerland / Liechtenstein
10080: {0x02A, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0)
10081: {0x02B, LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN}, // Austria (DR DOS 5.0)
10082: {0x02C, LANG_ENGLISH, SUBLANG_ENGLISH_UK}, // United Kingdom
10083: {0x02D, LANG_DANISH, SUBLANG_DANISH_DENMARK}, // Denmark
10084: {0x02E, LANG_SWEDISH, SUBLANG_SWEDISH}, // Sweden
10085: // {0x02E, LANG_SAMI, SUBLANG_SAMI_NORTHERN_SWEDEN}, // Sweden
10086: // {0x02E, LANG_SAMI, SUBLANG_SAMI_LULE_SWEDEN}, // Sweden
10087: // {0x02E, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_SWEDEN}, // Sweden
10088: {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL}, // Norway
10089: // {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK}, // Norway
10090: // {0x02F, LANG_SAMI, SUBLANG_SAMI_NORTHERN_NORWAY}, // Norway
10091: // {0x02F, LANG_SAMI, SUBLANG_SAMI_LULE_NORWAY}, // Norway
10092: // {0x02F, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_NORWAY}, // Norway
10093: {0x030, LANG_POLISH, SUBLANG_POLISH_POLAND}, // Poland (not supported by DR DOS 5.0)
10094: {0x031, LANG_GERMAN, SUBLANG_GERMAN}, // Germany
10095: {0x033, LANG_SPANISH, SUBLANG_SPANISH_PERU}, // Peru
10096: // {0x033, LANG_QUECHUA, SUBLANG_QUECHUA_PERU}, // Peru
10097: {0x034, LANG_SPANISH, SUBLANG_SPANISH_MEXICAN}, // Mexico
10098: {0x035, LANG_SPANISH, SUBLANG_NEUTRAL}, // Cuba
10099: {0x036, LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA}, // Argentina
10100: {0x037, LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN}, // Brazil (not supported by DR DOS 5.0)
10101: {0x038, LANG_SPANISH, SUBLANG_SPANISH_CHILE}, // Chile
10102: {0x039, LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA}, // Columbia
10103: {0x03A, LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA}, // Venezuela
10104: {0x03C, LANG_MALAY, SUBLANG_MALAY_MALAYSIA}, // Malaysia
10105: {0x03D, LANG_ENGLISH, SUBLANG_ENGLISH_AUS}, // International English / Australia
10106: {0x03E, LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA}, // Indonesia / East Timor
10107: {0x03F, LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES}, // Philippines
10108: {0x040, LANG_ENGLISH, SUBLANG_ENGLISH_NZ}, // New Zealand
10109: {0x041, LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE}, // Singapore
10110: // {0x041, LANG_ENGLISH, SUBLANG_ENGLISH_SINGAPORE}, // Singapore
10111: {0x042, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan???
10112: {0x051, LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN}, // Japan (DR DOS 5.0, MS-DOS 5.0+)
10113: {0x052, LANG_KOREAN, SUBLANG_KOREAN}, // South Korea (DR DOS 5.0)
10114: {0x054, LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM}, // Vietnam
10115: {0x056, LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED}, // China (MS-DOS 5.0+)
10116: {0x058, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (MS-DOS 5.0+)
10117: {0x05A, LANG_TURKISH, SUBLANG_TURKISH_TURKEY}, // Turkey (MS-DOS 5.0+)
10118: {0x05B, LANG_HINDI, SUBLANG_HINDI_INDIA}, // India
10119: {0x05C, LANG_URDU, SUBLANG_URDU_PAKISTAN}, // Pakistan
10120: {0x05D, LANG_PASHTO, SUBLANG_PASHTO_AFGHANISTAN}, // Afghanistan
10121: // {0x05D, LANG_DARI, SUBLANG_DARI_AFGHANISTAN}, // Afghanistan
10122: {0x05E, LANG_SINHALESE, SUBLANG_SINHALESE_SRI_LANKA}, // Sri Lanka
10123: // {0x05E, LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA}, // Sri Lanka
10124: {0x062, LANG_PERSIAN, SUBLANG_PERSIAN_IRAN}, // Iran
10125: {0x070, LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS}, // Belarus
10126: {0x0C8, LANG_THAI, SUBLANG_THAI_THAILAND}, // Thailand
10127: {0x0D4, LANG_ARABIC, SUBLANG_ARABIC_MOROCCO}, // Morocco
10128: {0x0D5, LANG_ARABIC, SUBLANG_ARABIC_ALGERIA}, // Algeria
10129: {0x0D8, LANG_ARABIC, SUBLANG_ARABIC_TUNISIA}, // Tunisia
10130: {0x0DA, LANG_ARABIC, SUBLANG_ARABIC_LIBYA}, // Libya
10131: {0x0DD, LANG_WOLOF, SUBLANG_WOLOF_SENEGAL}, // Senegal
10132: // {0x0DD, LANG_PULAR, SUBLANG_PULAR_SENEGAL}, // Senegal
10133: {0x0EA, LANG_HAUSA, SUBLANG_HAUSA_NIGERIA_LATIN}, // Nigeria
10134: // {0x0EA, LANG_YORUBA, SUBLANG_YORUBA_NIGERIA}, // Nigeria
10135: // {0x0EA, LANG_IGBO, SUBLANG_IGBO_NIGERIA}, // Nigeria
10136: {0x0FB, LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA}, // Ethiopia
10137: // {0x0FB, LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA}, // Ethiopia
10138: {0x0FE, LANG_SWAHILI, SUBLANG_SWAHILI}, // Kenya
10139: {0x107, LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE}, // Zimbabwe
10140: {0x10B, LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA}, // Botswana
10141: {0x12A, LANG_FAEROESE, SUBLANG_FAEROESE_FAROE_ISLANDS}, // Faroe Islands
10142: {0x12B, LANG_GREENLANDIC, SUBLANG_GREENLANDIC_GREENLAND}, // Greenland
10143: {0x15F, LANG_PORTUGUESE, SUBLANG_PORTUGUESE}, // Portugal
10144: {0x160, LANG_LUXEMBOURGISH, SUBLANG_LUXEMBOURGISH_LUXEMBOURG}, // Luxembourg
10145: // {0x160, LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG}, // Luxembourg
10146: // {0x160, LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG}, // Luxembourg
10147: {0x161, LANG_IRISH, SUBLANG_IRISH_IRELAND}, // Ireland
10148: // {0x161, LANG_ENGLISH, SUBLANG_ENGLISH_IRELAND}, // Ireland
10149: {0x162, LANG_ICELANDIC, SUBLANG_ICELANDIC_ICELAND}, // Iceland
10150: {0x163, LANG_ALBANIAN, SUBLANG_ALBANIAN_ALBANIA}, // Albania
10151: {0x164, LANG_MALTESE, SUBLANG_MALTESE_MALTA}, // Malta
10152: {0x166, LANG_FINNISH, SUBLANG_FINNISH_FINLAND}, // Finland
10153: // {0x166, LANG_SAMI, SUBLANG_SAMI_NORTHERN_FINLAND}, // Finland
10154: // {0x166, LANG_SAMI, SUBLANG_SAMI_SKOLT_FINLAND}, // Finland
10155: // {0x166, LANG_SAMI, SUBLANG_SAMI_INARI_FINLAND}, // Finland
10156: {0x167, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria
10157: {0x172, LANG_LITHUANIAN, SUBLANG_LITHUANIAN_LITHUANIA}, // Lithuania
10158: {0x173, LANG_LATVIAN, SUBLANG_LATVIAN_LATVIA}, // Latvia
10159: {0x174, LANG_ESTONIAN, SUBLANG_ESTONIAN_ESTONIA}, // Estonia
10160: {0x17D, LANG_SERBIAN, SUBLANG_SERBIAN_LATIN}, // Serbia / Montenegro
10161: {0x180, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia???
10162: {0x181, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia
10163: {0x182, LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA}, // Slovenia
10164: {0x183, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN}, // Bosnia-Herzegovina (Latin)
10165: {0x184, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC}, // Bosnia-Herzegovina (Cyrillic)
10166: {0x185, LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA}, // FYR Macedonia
10167: {0x1A5, LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC}, // Czech Republic
10168: {0x1A6, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Slovakia
10169: {0x1F5, LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE}, // Belize
10170: {0x1F6, LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA}, // Guatemala
10171: {0x1F7, LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR}, // El Salvador
10172: {0x1F8, LANG_SPANISH, SUBLANG_SPANISH_HONDURAS}, // Honduras
10173: {0x1F9, LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA}, // Nicraragua
10174: {0x1FA, LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA}, // Costa Rica
10175: {0x1FB, LANG_SPANISH, SUBLANG_SPANISH_PANAMA}, // Panama
10176: {0x24F, LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA}, // Bolivia
1.1.1.43 root 10177: // {0x24F, LANG_QUECHUA, SUBLANG_QUECHUA_BOLIVIA}, // Bolivia
1.1.1.42 root 10178: {0x251, LANG_SPANISH, SUBLANG_SPANISH_ECUADOR}, // Ecuador
10179: // {0x251, LANG_QUECHUA, SUBLANG_QUECHUA_ECUADOR}, // Ecuador
10180: {0x253, LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY}, // Paraguay
10181: {0x256, LANG_SPANISH, SUBLANG_SPANISH_URUGUAY}, // Uruguay
10182: {0x2A1, LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM}, // Brunei Darussalam
10183: {0x311, LANG_ARABIC, SUBLANG_NEUTRAL}, // Arabic (Middle East/Saudi Arabia/etc.)
10184: {0x324, LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE}, // Ukraine
10185: {0x352, LANG_KOREAN, SUBLANG_KOREAN}, // North Korea
10186: {0x354, LANG_CHINESE, SUBLANG_CHINESE_HONGKONG}, // Hong Kong
10187: {0x355, LANG_CHINESE, SUBLANG_CHINESE_MACAU}, // Macao
10188: {0x357, LANG_KHMER, SUBLANG_KHMER_CAMBODIA}, // Cambodia
10189: {0x370, LANG_BANGLA, SUBLANG_BANGLA_BANGLADESH}, // Bangladesh
10190: {0x376, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (DOS 6.22+)
10191: {0x3C0, LANG_DIVEHI, SUBLANG_DIVEHI_MALDIVES}, // Maldives
10192: {0x3C1, LANG_ARABIC, SUBLANG_ARABIC_LEBANON}, // Lebanon
10193: {0x3C2, LANG_ARABIC, SUBLANG_ARABIC_JORDAN}, // Jordan
10194: {0x3C3, LANG_ARABIC, SUBLANG_ARABIC_SYRIA}, // Syrian Arab Republic
10195: {0x3C4, LANG_ARABIC, SUBLANG_ARABIC_IRAQ}, // Ireq
10196: {0x3C5, LANG_ARABIC, SUBLANG_ARABIC_KUWAIT}, // Kuwait
10197: {0x3C6, LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA}, // Saudi Arabia
10198: {0x3C7, LANG_ARABIC, SUBLANG_ARABIC_YEMEN}, // Yemen
10199: {0x3C8, LANG_ARABIC, SUBLANG_ARABIC_OMAN}, // Oman
10200: {0x3CB, LANG_ARABIC, SUBLANG_ARABIC_UAE}, // United Arab Emirates
10201: {0x3CC, LANG_HEBREW, SUBLANG_HEBREW_ISRAEL}, // Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+)
10202: {0x3CD, LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN}, // Bahrain
10203: {0x3CE, LANG_ARABIC, SUBLANG_ARABIC_QATAR}, // Qatar
10204: {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA}, // Mongolia
10205: // {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_PRC}, // Mongolia
10206: {0x3D1, LANG_NEPALI, SUBLANG_NEPALI_NEPAL}, // Nepal
10207: {-1, 0, 0},
10208: };
10209:
1.1.1.14 root 10210: inline void msdos_int_21h_38h()
10211: {
10212: switch(REG8(AL)) {
10213: case 0x00:
1.1.1.19 root 10214: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 10215: break;
10216: default:
1.1.1.42 root 10217: for(int i = 0;; i++) {
10218: if(country_table[i].code == (REG8(AL) != 0xff ? REG8(AL) : REG16(BX))) {
10219: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
10220: break;
10221: } else if(country_table[i].code == -1) {
10222: // 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));
10223: // REG16(AX) = 2;
10224: // m_CF = 1;
1.1.1.48 root 10225: // get current coutry info
1.1.1.42 root 10226: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
10227: break;
10228: }
10229: }
1.1.1.14 root 10230: break;
10231: }
10232: }
10233:
1.1 root 10234: inline void msdos_int_21h_39h(int lfn)
10235: {
1.1.1.3 root 10236: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10237: REG16(AX) = errno;
1.1.1.3 root 10238: m_CF = 1;
1.1 root 10239: }
10240: }
10241:
10242: inline void msdos_int_21h_3ah(int lfn)
10243: {
1.1.1.3 root 10244: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10245: REG16(AX) = errno;
1.1.1.3 root 10246: m_CF = 1;
1.1 root 10247: }
10248: }
10249:
10250: inline void msdos_int_21h_3bh(int lfn)
10251: {
1.1.1.45 root 10252: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1.1.44 root 10253:
10254: if(_chdir(path)) {
1.1.1.17 root 10255: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 10256: m_CF = 1;
1.1.1.44 root 10257: } else {
10258: int drv = _getdrive() - 1;
10259: if(path[1] == ':') {
10260: if(path[0] >= 'A' && path[0] <= 'Z') {
10261: drv = path[0] - 'A';
10262: } else if(path[0] >= 'a' && path[0] <= 'z') {
10263: drv = path[0] - 'a';
10264: }
10265: }
10266: msdos_cds_update(drv, path);
1.1 root 10267: }
10268: }
10269:
10270: inline void msdos_int_21h_3ch()
10271: {
1.1.1.45 root 10272: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10273: int attr = GetFileAttributes(path);
1.1.1.37 root 10274: int fd = -1;
10275: int sio_port = 0;
10276: int lpt_port = 0;
1.1 root 10277:
1.1.1.45 root 10278: if(msdos_is_device_path(path)) {
10279: fd = msdos_open_device(path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port);
1.1 root 10280: } else {
10281: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10282: }
10283: if(fd != -1) {
10284: if(attr == -1) {
10285: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
10286: }
10287: SetFileAttributes(path, attr);
10288: REG16(AX) = fd;
1.1.1.45 root 10289: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 10290: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10291: } else {
10292: REG16(AX) = errno;
1.1.1.3 root 10293: m_CF = 1;
1.1 root 10294: }
10295: }
10296:
10297: inline void msdos_int_21h_3dh()
10298: {
1.1.1.45 root 10299: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10300: int mode = REG8(AL) & 0x03;
1.1.1.37 root 10301: int fd = -1;
10302: int sio_port = 0;
10303: int lpt_port = 0;
1.1 root 10304:
10305: if(mode < 0x03) {
1.1.1.45 root 10306: if(msdos_is_device_path(path)) {
10307: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
1.1.1.11 root 10308: } else {
1.1.1.13 root 10309: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 10310: }
1.1 root 10311: if(fd != -1) {
10312: REG16(AX) = fd;
1.1.1.45 root 10313: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 10314: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10315: } else {
10316: REG16(AX) = errno;
1.1.1.3 root 10317: m_CF = 1;
1.1 root 10318: }
10319: } else {
10320: REG16(AX) = 0x0c;
1.1.1.3 root 10321: m_CF = 1;
1.1 root 10322: }
10323: }
10324:
10325: inline void msdos_int_21h_3eh()
10326: {
10327: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10328: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10329:
1.1.1.20 root 10330: if(fd < process->max_files && file_handler[fd].valid) {
10331: _close(fd);
10332: msdos_file_handler_close(fd);
10333: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 10334: } else {
10335: REG16(AX) = 0x06;
1.1.1.3 root 10336: m_CF = 1;
1.1 root 10337: }
10338: }
10339:
1.1.1.35 root 10340: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID)
10341: {
10342: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
10343: int max = REG16(CX);
10344: int p = 0;
10345:
10346: while(max > p) {
10347: int chr = msdos_getch();
10348:
10349: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
10350: p = 0;
10351: buf[p++] = 0x0d;
10352: if(max > p) {
10353: buf[p++] = 0x0a;
10354: }
10355: msdos_putch(0x03);
10356: msdos_putch(0x0d);
10357: msdos_putch(0x0a);
10358: break;
10359: } else if(ctrl_break_pressed) {
10360: // skip this byte
10361: } else if(chr == 0x00) {
10362: // skip 2nd byte
10363: msdos_getch();
10364: } else if(chr == 0x0d) {
10365: // carriage return
10366: buf[p++] = 0x0d;
10367: if(max > p) {
10368: buf[p++] = 0x0a;
10369: }
10370: msdos_putch('\n');
10371: break;
10372: } else if(chr == 0x08) {
10373: // back space
10374: if(p > 0) {
10375: p--;
10376: if(msdos_ctrl_code_check(buf[p])) {
10377: msdos_putch(0x08);
10378: msdos_putch(0x08);
10379: msdos_putch(0x20);
10380: msdos_putch(0x20);
10381: msdos_putch(0x08);
10382: msdos_putch(0x08);
1.1.1.36 root 10383: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
10384: p--;
10385: msdos_putch(0x08);
10386: msdos_putch(0x08);
10387: msdos_putch(0x20);
10388: msdos_putch(0x20);
10389: msdos_putch(0x08);
10390: msdos_putch(0x08);
1.1.1.35 root 10391: } else {
10392: msdos_putch(0x08);
10393: msdos_putch(0x20);
10394: msdos_putch(0x08);
10395: }
10396: }
10397: } else if(chr == 0x1b) {
10398: // escape
10399: while(p > 0) {
10400: p--;
10401: if(msdos_ctrl_code_check(buf[p])) {
10402: msdos_putch(0x08);
10403: msdos_putch(0x08);
10404: msdos_putch(0x20);
10405: msdos_putch(0x20);
10406: msdos_putch(0x08);
10407: msdos_putch(0x08);
10408: } else {
10409: msdos_putch(0x08);
10410: msdos_putch(0x20);
10411: msdos_putch(0x08);
10412: }
10413: }
10414: } else {
10415: buf[p++] = chr;
10416: msdos_putch(chr);
10417: }
10418: }
10419: REG16(AX) = p;
10420:
10421: #ifdef USE_SERVICE_THREAD
10422: service_exit = true;
10423: #endif
10424: return(0);
10425: }
10426:
1.1 root 10427: inline void msdos_int_21h_3fh()
10428: {
10429: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10430: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10431:
1.1.1.20 root 10432: if(fd < process->max_files && file_handler[fd].valid) {
10433: if(file_mode[file_handler[fd].mode].in) {
10434: if(file_handler[fd].atty) {
1.1 root 10435: // BX is stdin or is redirected to stdin
1.1.1.35 root 10436: if(REG16(CX) != 0) {
10437: #ifdef USE_SERVICE_THREAD
10438: start_service_loop(msdos_int_21h_3fh_thread);
10439: #else
10440: msdos_int_21h_3fh_thread(NULL);
10441: REQUEST_HARDWRE_UPDATE();
10442: #endif
10443: } else {
10444: REG16(AX) = 0;
1.1 root 10445: }
10446: } else {
1.1.1.37 root 10447: REG16(AX) = msdos_read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10448: }
10449: } else {
10450: REG16(AX) = 0x05;
1.1.1.3 root 10451: m_CF = 1;
1.1 root 10452: }
10453: } else {
10454: REG16(AX) = 0x06;
1.1.1.3 root 10455: m_CF = 1;
1.1 root 10456: }
10457: }
10458:
10459: inline void msdos_int_21h_40h()
10460: {
10461: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10462: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10463:
1.1.1.20 root 10464: if(fd < process->max_files && file_handler[fd].valid) {
10465: if(file_mode[file_handler[fd].mode].out) {
1.1 root 10466: if(REG16(CX)) {
1.1.1.20 root 10467: if(file_handler[fd].atty) {
1.1 root 10468: // BX is stdout/stderr or is redirected to stdout
10469: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 10470: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 10471: }
10472: REG16(AX) = REG16(CX);
10473: } else {
1.1.1.20 root 10474: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10475: }
10476: } else {
1.1.1.20 root 10477: UINT32 pos = _tell(fd);
10478: _lseek(fd, 0, SEEK_END);
10479: UINT32 size = _tell(fd);
1.1.1.12 root 10480: if(pos < size) {
1.1.1.20 root 10481: _lseek(fd, pos, SEEK_SET);
10482: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 10483: } else {
10484: for(UINT32 i = size; i < pos; i++) {
10485: UINT8 tmp = 0;
1.1.1.23 root 10486: msdos_write(fd, &tmp, 1);
1.1.1.12 root 10487: }
1.1.1.20 root 10488: _lseek(fd, pos, SEEK_SET);
1.1 root 10489: }
1.1.1.23 root 10490: REG16(AX) = 0;
1.1 root 10491: }
10492: } else {
10493: REG16(AX) = 0x05;
1.1.1.3 root 10494: m_CF = 1;
1.1 root 10495: }
10496: } else {
10497: REG16(AX) = 0x06;
1.1.1.3 root 10498: m_CF = 1;
1.1 root 10499: }
10500: }
10501:
10502: inline void msdos_int_21h_41h(int lfn)
10503: {
1.1.1.3 root 10504: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10505: REG16(AX) = errno;
1.1.1.3 root 10506: m_CF = 1;
1.1 root 10507: }
10508: }
10509:
10510: inline void msdos_int_21h_42h()
10511: {
10512: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10513: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10514:
1.1.1.20 root 10515: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 10516: if(REG8(AL) < 0x03) {
1.1.1.35 root 10517: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 10518: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
10519: UINT32 pos = _tell(fd);
1.1 root 10520: REG16(AX) = pos & 0xffff;
10521: REG16(DX) = (pos >> 16);
10522: } else {
10523: REG16(AX) = 0x01;
1.1.1.3 root 10524: m_CF = 1;
1.1 root 10525: }
10526: } else {
10527: REG16(AX) = 0x06;
1.1.1.3 root 10528: m_CF = 1;
1.1 root 10529: }
10530: }
10531:
10532: inline void msdos_int_21h_43h(int lfn)
10533: {
1.1.1.45 root 10534: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 10535: int attr;
10536:
1.1.1.14 root 10537: if(!lfn && REG8(AL) > 2) {
10538: REG16(AX) = 0x01;
10539: m_CF = 1;
10540: return;
10541: }
10542: switch(REG8(lfn ? BL : AL)) {
1.1 root 10543: case 0x00:
10544: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 10545: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
10546: } else {
10547: REG16(AX) = (UINT16)GetLastError();
10548: m_CF = 1;
10549: }
10550: break;
10551: case 0x01:
10552: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
10553: REG16(AX) = (UINT16)GetLastError();
10554: m_CF = 1;
10555: }
10556: break;
10557: case 0x02:
10558: {
1.1.1.45 root 10559: DWORD compressed_size = GetCompressedFileSize(path, NULL), file_size = 0;
10560: if(compressed_size != INVALID_FILE_SIZE) {
10561: if(compressed_size != 0) {
10562: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10563: if(hFile != INVALID_HANDLE_VALUE) {
10564: file_size = GetFileSize(hFile, NULL);
10565: CloseHandle(hFile);
10566: }
10567: if(compressed_size == file_size) {
10568: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
10569: // this isn't correct if the file is in the NTFS MFT
10570: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
10571: compressed_size = ((compressed_size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
10572: }
1.1.1.14 root 10573: }
10574: }
1.1.1.45 root 10575: REG16(AX) = LOWORD(compressed_size);
10576: REG16(DX) = HIWORD(compressed_size);
1.1.1.14 root 10577: } else {
10578: REG16(AX) = (UINT16)GetLastError();
10579: m_CF = 1;
1.1 root 10580: }
1.1.1.14 root 10581: }
10582: break;
10583: case 0x03:
10584: case 0x05:
10585: case 0x07:
1.1.1.48 root 10586: if(lfn) {
1.1.1.14 root 10587: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10588: if(hFile != INVALID_HANDLE_VALUE) {
10589: FILETIME local, time;
10590: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
10591: if(REG8(BL) == 7) {
10592: ULARGE_INTEGER hund;
10593: hund.LowPart = local.dwLowDateTime;
10594: hund.HighPart = local.dwHighDateTime;
10595: hund.QuadPart += REG16(SI) * 100000;
10596: local.dwLowDateTime = hund.LowPart;
10597: local.dwHighDateTime = hund.HighPart;
10598: }
10599: LocalFileTimeToFileTime(&local, &time);
10600: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
10601: REG8(BL) == 0x05 ? &time : NULL,
10602: REG8(BL) == 0x03 ? &time : NULL)) {
10603: REG16(AX) = (UINT16)GetLastError();
10604: m_CF = 1;
10605: }
10606: CloseHandle(hFile);
10607: } else {
10608: REG16(AX) = (UINT16)GetLastError();
10609: m_CF = 1;
1.1 root 10610: }
1.1.1.48 root 10611: } else {
10612: // 214303 DR DOS 3.41+ internal - Set Access Rights And Password
10613: // 214305 DR DOS 5.0-6.0 internal - Set Extended File Attributes
10614: // 214307 DR DOS 6.0 - Set File Owner
10615: // 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));
10616: REG16(AX) = 0x01;
10617: m_CF = 1;
1.1.1.14 root 10618: }
10619: break;
10620: case 0x04:
10621: case 0x06:
10622: case 0x08:
1.1.1.48 root 10623: if(lfn) {
1.1.1.14 root 10624: WIN32_FILE_ATTRIBUTE_DATA fad;
10625: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
10626: FILETIME *time, local;
10627: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
10628: 0x06 ? &fad.ftLastAccessTime :
10629: &fad.ftCreationTime;
10630: FileTimeToLocalFileTime(time, &local);
10631: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
10632: if(REG8(BL) == 0x08) {
10633: ULARGE_INTEGER hund;
10634: hund.LowPart = local.dwLowDateTime;
10635: hund.HighPart = local.dwHighDateTime;
10636: hund.QuadPart /= 100000;
10637: REG16(SI) = (UINT16)(hund.QuadPart % 200);
10638: }
10639: } else {
10640: REG16(AX) = (UINT16)GetLastError();
10641: m_CF = 1;
1.1 root 10642: }
1.1.1.48 root 10643: } else {
10644: // 214304 DR DOS 5.0-6.0 internal - Get Encrypted Password
10645: // 214306 DR DOS 6.0 - Get File Owner
10646: // 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));
10647: REG16(AX) = 0x01;
10648: m_CF = 1;
1.1.1.14 root 10649: }
10650: break;
1.1.1.43 root 10651: case 0xff:
1.1.1.48 root 10652: if(!lfn && REG16(BP) == 0x5053) {
1.1.1.43 root 10653: if(REG8(CL) == 0x39) {
10654: msdos_int_21h_39h(1);
10655: break;
10656: } else if(REG8(CL) == 0x56) {
10657: msdos_int_21h_56h(1);
10658: break;
10659: }
10660: }
1.1.1.14 root 10661: default:
1.1.1.22 root 10662: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 10663: REG16(AX) = lfn ? 0x7100 : 0x01;
1.1.1.14 root 10664: m_CF = 1;
10665: break;
10666: }
10667: }
10668:
10669: inline void msdos_int_21h_44h()
10670: {
1.1.1.22 root 10671: static UINT16 iteration_count = 0;
10672:
1.1.1.44 root 10673: process_t *process;
10674: int fd, drv;
1.1.1.14 root 10675:
10676: switch(REG8(AL)) {
10677: case 0x00:
10678: case 0x01:
10679: case 0x02:
10680: case 0x03:
10681: case 0x04:
10682: case 0x05:
10683: case 0x06:
10684: case 0x07:
1.1.1.44 root 10685: process = msdos_process_info_get(current_psp);
10686: fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1.1.20 root 10687: if(fd >= process->max_files || !file_handler[fd].valid) {
10688: REG16(AX) = 0x06;
10689: m_CF = 1;
10690: return;
1.1.1.14 root 10691: }
10692: break;
10693: case 0x08:
10694: case 0x09:
1.1.1.44 root 10695: drv = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
10696: if(!msdos_is_valid_drive(drv)) {
10697: // invalid drive
1.1.1.14 root 10698: REG16(AX) = 0x0f;
10699: m_CF = 1;
10700: return;
1.1 root 10701: }
10702: break;
10703: }
10704: switch(REG8(AL)) {
1.1.1.48 root 10705: case 0x00: // Get Device Information
1.1.1.20 root 10706: REG16(DX) = file_handler[fd].info;
1.1 root 10707: break;
1.1.1.48 root 10708: case 0x01: // Set Device Information
1.1.1.45 root 10709: if(REG8(DH) != 0) {
10710: // REG16(AX) = 0x0d; // data invalid
10711: // m_CF = 1;
10712: file_handler[fd].info = REG16(DX);
10713: } else {
10714: file_handler[fd].info &= 0xff00;
10715: file_handler[fd].info |= REG8(DL);
10716: }
1.1 root 10717: break;
1.1.1.48 root 10718: case 0x02: // Read From Character Device Control Channel
1.1.1.45 root 10719: if(strstr(file_handler[fd].path, "EMMXXXX0") != NULL && support_ems) {
10720: // from DOSBox
10721: switch(*(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX))) {
10722: case 0x00:
10723: if(REG16(CX) >= 6) {
10724: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0023;
10725: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0000;
10726: REG16(AX) = 6; // number of bytes actually read
10727: } else {
10728: REG16(AX) = 0x0d; // data invalid
10729: m_CF = 1;
10730: }
10731: break;
10732: case 0x01:
10733: if(REG16(CX) >= 6) {
10734: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x000) = 0x0004; // flags
10735: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x002) = 0x019d; // size of this structure
10736: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x004) = 0x0001; // version 1.0
10737: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x006) = 0x00000000; // reserved
10738: for(int addr = 0, ofs = 0x00a; addr < 0x100000; addr += 0x4000, ofs += 6) {
10739: if(addr >= EMS_TOP && addr < EMS_TOP + EMS_SIZE) {
10740: int page = (addr - EMS_TOP) / 0x4000;
10741: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x03; // frame type: EMS frame in 64k page
10742: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE
10743: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0x7fff; // no logical page number
10744: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = page; // physical EMS page number
10745: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0x00; // flags: EMS frame
10746: } else {
10747: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x00; // frame type: NONE
10748: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE
10749: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0xffff; // non-EMS frame
10750: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = 0xff; // EMS page number (NONE)
10751: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0xaa; // flags: direct mapping
10752: }
10753: }
10754: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18a) = 0x74; // ??
10755: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18b) = 0x00; // no UMB descriptors following
10756: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18c) = 0x01; // 1 EMS handle info record
10757: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x17d) = 0x0000; // system handle
10758: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x18f) = 0x00000000; // handle name
10759: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x193) = 0x00000000; // handle name
10760: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x197) = 0x0001; // system handle
10761: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x199) = 0x00110000; // physical address
10762:
10763: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0018;
10764: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = XMS_TOP >> 4;;
10765: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4) = 0x0001; // version 1.0
10766: REG16(AX) = 6; // number of bytes actually read
10767: } else {
10768: REG16(AX) = 0x0d; // data invalid
10769: m_CF = 1;
10770: }
10771: break;
10772: case 0x02:
10773: if(REG16(CX) >= 2) {
10774: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x40; // EMS 4.0
10775: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 1) = 0x00;
10776: REG16(AX) = 2; // number of bytes actually read
10777: } else {
10778: REG16(AX) = 0x0d; // data invalid
10779: m_CF = 1;
10780: }
10781: break;
10782: case 0x03:
10783: if(REG16(CX) >= 4) {
10784: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = MAX_EMS_PAGES * 16; // max size (kb)
10785: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0080; // min size (kb)
10786: REG16(AX) = 4; // number of bytes actually read
10787: } else {
10788: REG16(AX) = 0x0d; // data invalid
10789: m_CF = 1;
10790: }
10791: break;
10792: default:
10793: REG16(AX) = 0x01; // function number invalid
10794: m_CF = 1;
10795: }
10796: } else if(strstr(file_handler[fd].path, "CONFIG$") != NULL) {
10797: if(REG16(CX) >= 5) {
10798: memset(mem + SREG_BASE(DS) + REG16(DX), 0, 5);
10799: REG16(AX) = 5; // number of bytes actually read
10800: } else {
10801: REG16(AX) = 0x0d; // data invalid
10802: m_CF = 1;
10803: }
10804: } else {
10805: // memset(mem + SREG_BASE(DS) + REG16(DX), 0, REG16(CX));
10806: // REG16(AX) = REG16(CX);
10807: REG16(AX) = 0x05; // access denied
10808: m_CF = 1;
10809: }
10810: break;
1.1.1.48 root 10811: case 0x03: // Write To Character Device Control Channel
1.1.1.45 root 10812: // REG16(AX) = 0x05;
10813: // m_CF = 1;
10814: REG16(AX) = 0x00; // success
10815: break;
1.1.1.48 root 10816: case 0x04: // Read From Block Device Control Channel
10817: case 0x05: // Write To Block Device Control Channel
1.1 root 10818: REG16(AX) = 0x05;
1.1.1.3 root 10819: m_CF = 1;
1.1 root 10820: break;
1.1.1.48 root 10821: case 0x06: // Get Input Status
1.1.1.20 root 10822: if(file_mode[file_handler[fd].mode].in) {
10823: if(file_handler[fd].atty) {
1.1.1.14 root 10824: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 10825: } else {
1.1.1.20 root 10826: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 10827: }
1.1.1.14 root 10828: } else {
10829: REG8(AL) = 0x00;
1.1 root 10830: }
10831: break;
1.1.1.48 root 10832: case 0x07: // Get Output Status
1.1.1.20 root 10833: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 10834: REG8(AL) = 0xff;
10835: } else {
10836: REG8(AL) = 0x00;
1.1 root 10837: }
10838: break;
1.1.1.48 root 10839: case 0x08: // Check If Block Device Removable
1.1.1.44 root 10840: if(msdos_is_removable_drive(drv) || msdos_is_cdrom_drive(drv)) {
1.1.1.14 root 10841: // removable drive
10842: REG16(AX) = 0x00;
1.1 root 10843: } else {
1.1.1.14 root 10844: // fixed drive
10845: REG16(AX) = 0x01;
1.1 root 10846: }
10847: break;
1.1.1.48 root 10848: case 0x09: // Check If Block Device Remote
1.1.1.44 root 10849: if(msdos_is_remote_drive(drv)) {
1.1.1.14 root 10850: // remote drive
10851: REG16(DX) = 0x1000;
1.1.1.44 root 10852: } else if(msdos_is_subst_drive(drv)) {
10853: // subst drive
10854: REG16(DX) = 0x8000;
1.1 root 10855: } else {
1.1.1.14 root 10856: // local drive
1.1.1.44 root 10857: REG16(DX) = 0x0000;
1.1 root 10858: }
10859: break;
1.1.1.48 root 10860: case 0x0a: // Check If Handle Is Remote
1.1.1.45 root 10861: if(!(file_handler[fd].info & 0x8000) && msdos_is_remote_drive(msdos_drive_number(file_handler[fd].path))) {
10862: REG16(DX) = 0x8000;
10863: } else {
10864: REG16(DX) = 0x0000;
10865: }
1.1.1.21 root 10866: break;
1.1.1.48 root 10867: case 0x0b: // Set Sharing Retry Count
1.1 root 10868: break;
1.1.1.48 root 10869: case 0x0c: // Generic Character Device Request
1.1.1.22 root 10870: if(REG8(CL) == 0x45) {
10871: // set iteration (retry) count
10872: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
10873: } else if(REG8(CL) == 0x4a) {
10874: // select code page
10875: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
10876: msdos_nls_tables_update();
1.1.1.44 root 10877: } else if(REG8(CL) == 0x4c) {
10878: // start code-page preparation
10879: int ids[3] = {437, 0, 0}; // 437: US English
10880: int count = 1, offset = 0;
10881: if(active_code_page != 437) {
10882: ids[count++] = active_code_page;
10883: }
10884: if(system_code_page != 437 && system_code_page != active_code_page) {
10885: ids[count++] = system_code_page;
10886: }
10887: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 0;
10888: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 + 2 * count;
10889: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
10890: for(int i = 0; i < count; i++) {
10891: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
10892: }
10893: } else if(REG8(CL) == 0x4d) {
10894: // end code-page preparation
10895: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2;
10896: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
1.1.1.48 root 10897: // } else if(REG8(CL) == 0x5f) {
10898: // // set display information
1.1.1.22 root 10899: } else if(REG8(CL) == 0x65) {
10900: // get iteration (retry) count
10901: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
10902: } else if(REG8(CL) == 0x6a) {
10903: // query selected code page
10904: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
10905: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
10906:
10907: CPINFO info;
10908: GetCPInfo(active_code_page, &info);
10909:
10910: if(info.MaxCharSize != 1) {
10911: for(int i = 0;; i++) {
10912: UINT8 lo = info.LeadByte[2 * i + 0];
10913: UINT8 hi = info.LeadByte[2 * i + 1];
10914:
10915: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
10916: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
10917: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
10918:
10919: if(lo == 0 && hi == 0) {
10920: break;
10921: }
10922: }
10923: }
1.1.1.44 root 10924: } else if(REG8(CL) == 0x6b) {
10925: // query prepare list
10926: int ids[3] = {437, 0, 0}; // 437: US English
10927: int count = 1, offset = 0;
10928: if(active_code_page != 437) {
10929: ids[count++] = active_code_page;
10930: }
10931: if(system_code_page != 437 && system_code_page != active_code_page) {
10932: ids[count++] = system_code_page;
10933: }
10934: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 * (2 + 2 * count);
10935: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
10936: for(int i = 0; i < count; i++) {
10937: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
10938: }
10939: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count;
10940: for(int i = 0; i < count; i++) {
10941: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i];
10942: }
1.1.1.22 root 10943: } else if(REG8(CL) == 0x7f) {
1.1.1.44 root 10944: // get display information
1.1.1.22 root 10945: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
10946: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
10947: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
10948: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
10949: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
10950: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
10951: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
10952: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
10953: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
10954: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
10955: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
10956: } else {
10957: 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));
10958: REG16(AX) = 0x01; // invalid function
10959: m_CF = 1;
10960: }
10961: break;
1.1.1.48 root 10962: case 0x0d: // Generic Block Device Request
1.1.1.22 root 10963: if(REG8(CL) == 0x40) {
10964: // set device parameters
1.1.1.48 root 10965: // } else if(REG8(CL) == 0x41) {
10966: // // write logical device track
10967: // } else if(REG8(CL) == 0x42) {
10968: // // format and verify logical device track
1.1.1.22 root 10969: } else if(REG8(CL) == 0x46) {
10970: // set volume serial number
1.1.1.48 root 10971: } else if(REG8(CL) == 0x47) {
10972: // set access flag
10973: // } else if(REG8(CL) == 0x48) {
10974: // // set media lock state
10975: // } else if(REG8(CL) == 0x49) {
10976: // // eject media in drive
1.1.1.22 root 10977: } else if(REG8(CL) == 0x4a) {
10978: // lock logical volume
10979: } else if(REG8(CL) == 0x4b) {
10980: // lock physical volume
10981: } else if(REG8(CL) == 0x60) {
10982: // get device parameters
1.1.1.42 root 10983: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
1.1.1.22 root 10984:
1.1.1.42 root 10985: if(pcbios_update_drive_param(drive_num, 1)) {
10986: drive_param_t *drive_param = &drive_params[drive_num];
10987: DISK_GEOMETRY *geo = &drive_param->geometry;
10988:
10989: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
10990: switch(geo->MediaType) {
10991: case F5_360_512:
10992: case F5_320_512:
10993: case F5_320_1024:
10994: case F5_180_512:
10995: case F5_160_512:
10996: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
10997: break;
10998: case F5_1Pt2_512:
10999: case F3_1Pt2_512:
11000: case F3_1Pt23_1024:
11001: case F5_1Pt23_1024:
11002: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
11003: break;
11004: case F3_720_512:
11005: case F3_640_512:
11006: case F5_640_512:
11007: case F5_720_512:
11008: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
11009: break;
11010: case F8_256_128:
11011: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
11012: break;
11013: case FixedMedia:
11014: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
11015: break;
11016: case F3_1Pt44_512:
11017: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
11018: break;
11019: case F3_2Pt88_512:
11020: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
11021: break;
11022: default:
11023: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
11024: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
11025: break;
1.1.1.22 root 11026: }
1.1.1.42 root 11027: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo->MediaType == FixedMedia) ? 0x01 : 0x00;
11028: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo->Cylinders.QuadPart > 0xffff) ? 0xffff : geo->Cylinders.QuadPart;
11029: switch(geo->MediaType) {
11030: case F5_360_512:
11031: case F5_320_512:
11032: case F5_320_1024:
11033: case F5_180_512:
11034: case F5_160_512:
11035: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
11036: break;
11037: default:
11038: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
11039: break;
11040: }
11041: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo->BytesPerSector;
11042: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo->SectorsPerTrack * geo->TracksPerCylinder;
11043: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
11044: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
11045: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
11046: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
11047: switch(geo->MediaType) {
11048: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
11049: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
11050: break;
11051: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
11052: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
11053: break;
11054: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
11055: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
11056: break;
11057: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
11058: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
11059: break;
11060: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
11061: case F3_1Pt2_512:
11062: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
11063: case F5_720_512:
11064: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
11065: break;
11066: case FixedMedia: // hard disk
11067: case RemovableMedia:
11068: case Unknown:
11069: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
11070: break;
11071: default:
11072: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
11073: break;
11074: }
11075: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo->SectorsPerTrack;
11076: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
11077: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
11078: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo->TracksPerCylinder * geo->Cylinders.QuadPart;
11079: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo->Cylinders.QuadPart;
11080: // 21h BYTE device type
11081: // 22h WORD device attributes (removable or not, etc)
1.1.1.22 root 11082: } else {
11083: REG16(AX) = 0x0f; // invalid drive
11084: m_CF = 1;
11085: }
1.1.1.48 root 11086: // } else if(REG8(CL) == 0x61) {
11087: // // read logical device track
11088: // } else if(REG8(CL) == 0x62) {
11089: // // verify logical device track
1.1.1.22 root 11090: } else if(REG8(CL) == 0x66) {
11091: // get volume serial number
11092: char path[] = "A:\\";
11093: char volume_label[MAX_PATH];
11094: DWORD serial_number = 0;
11095: char file_system[MAX_PATH];
11096:
11097: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
11098:
11099: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
11100: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
11101: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
11102: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
11103: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
11104: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
11105: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
11106: } else {
11107: REG16(AX) = 0x0f; // invalid drive
11108: m_CF = 1;
11109: }
11110: } else if(REG8(CL) == 0x67) {
11111: // get access flag
11112: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
11113: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
11114: } else if(REG8(CL) == 0x68) {
11115: // sense media type
1.1.1.42 root 11116: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
1.1.1.22 root 11117:
1.1.1.42 root 11118: if(pcbios_update_drive_param(drive_num, 1)) {
11119: drive_param_t *drive_param = &drive_params[drive_num];
11120: DISK_GEOMETRY *geo = &drive_param->geometry;
11121:
11122: switch(geo->MediaType) {
11123: case F3_720_512:
11124: case F5_720_512:
11125: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
11126: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
11127: break;
11128: case F3_1Pt44_512:
11129: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
11130: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
11131: break;
11132: case F3_2Pt88_512:
11133: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
11134: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
11135: break;
11136: default:
11137: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
11138: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
11139: break;
1.1.1.22 root 11140: }
11141: } else {
11142: REG16(AX) = 0x0f; // invalid drive
11143: m_CF = 1;
11144: }
11145: } else if(REG8(CL) == 0x6a) {
11146: // unlock logical volume
11147: } else if(REG8(CL) == 0x6b) {
11148: // unlock physical volume
1.1.1.48 root 11149: // } else if(REG8(CL) == 0x6c) {
11150: // // get lock flag
11151: // } else if(REG8(CL) == 0x6d) {
11152: // // enumerate open files
11153: // } else if(REG8(CL) == 0x6e) {
11154: // // find swap file
11155: // } else if(REG8(CL) == 0x6f) {
11156: // // get drive map information
11157: // } else if(REG8(CL) == 0x70) {
11158: // // get current lock state
11159: // } else if(REG8(CL) == 0x71) {
11160: // // get first cluster
1.1.1.22 root 11161: } else {
11162: 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));
11163: REG16(AX) = 0x01; // invalid function
11164: m_CF = 1;
11165: }
11166: break;
1.1.1.48 root 11167: case 0x0e: // Get Lgical Drive Map
1.1.1.44 root 11168: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
11169: REG16(AX) = 0x0f; // invalid drive
11170: m_CF = 1;
11171: } else {
11172: REG8(AL) = 0;
1.1.1.22 root 11173: }
11174: break;
1.1.1.48 root 11175: case 0x0f: // Set Logical Drive Map
1.1.1.44 root 11176: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
11177: REG16(AX) = 0x0f; // invalid drive
11178: m_CF = 1;
1.1.1.22 root 11179: }
11180: break;
1.1.1.48 root 11181: case 0x10: // Query Generic IOCTRL Capability (Handle)
1.1.1.22 root 11182: switch(REG8(CL)) {
11183: case 0x45:
11184: case 0x4a:
1.1.1.48 root 11185: case 0x4c:
11186: case 0x4d:
1.1.1.22 root 11187: case 0x65:
11188: case 0x6a:
1.1.1.48 root 11189: case 0x6b:
1.1.1.22 root 11190: case 0x7f:
11191: REG16(AX) = 0x0000; // supported
11192: break;
11193: default:
11194: REG8(AL) = 0x01; // ioctl capability not available
11195: m_CF = 1;
11196: break;
11197: }
11198: break;
1.1.1.48 root 11199: case 0x11: // Query Generic IOCTRL Capability (Drive)
1.1.1.22 root 11200: switch(REG8(CL)) {
11201: case 0x40:
11202: case 0x46:
11203: case 0x4a:
11204: case 0x4b:
11205: case 0x60:
11206: case 0x66:
11207: case 0x67:
11208: case 0x68:
11209: case 0x6a:
11210: case 0x6b:
1.1.1.48 root 11211: if(REG8(CH) == 0x00 || REG8(CH) == 0x01 || REG8(CH) == 0x03 || REG8(CH) == 0x05) {
11212: // CH = 00h Unknown
11213: // CH = 01h COMn:
11214: // CH = 03h CON
11215: // CH = 05h LPTn:
11216: REG16(AX) = 0x0000; // supported
11217: break;
11218: }
1.1.1.22 root 11219: default:
11220: REG8(AL) = 0x01; // ioctl capability not available
11221: m_CF = 1;
11222: break;
11223: }
11224: break;
1.1.1.48 root 11225: case 0x12: // DR DOS 5.0-6.0 - Determine DOS Type
11226: case 0x14: // DR DOS 5.0-6.0 - Set Global Password
11227: case 0x16: // DR DOS 5.0-6.0 - History Buffer, Share, And Hiload Control
11228: case 0x51: // Concurrent DOS v3.2+ - Installation Check
11229: case 0x52: // DR DOS 3.41+ - Determine DOS tTpe/Get DR DOS Version
11230: case 0x54: // DR DOS 3.41+ - Set Global Password
11231: case 0x56: // DR DOS 5.0+ - History Buffer Control
11232: case 0x57: // DR DOS 5.0-6.0 - Share/Hiload Control
11233: case 0x58: // DR DOS 5.0+ internal - Get Pointer To Internal Variable Table
11234: case 0x59: // DR Multiuser DOS 5.0 - API
11235: REG16(AX) = 0x01; // this is not DR-DOS
1.1.1.22 root 11236: m_CF = 1;
11237: break;
1.1 root 11238: default:
1.1.1.22 root 11239: 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 11240: REG16(AX) = 0x01;
1.1.1.3 root 11241: m_CF = 1;
1.1 root 11242: break;
11243: }
11244: }
11245:
11246: inline void msdos_int_21h_45h()
11247: {
11248: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11249: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 11250:
1.1.1.20 root 11251: if(fd < process->max_files && file_handler[fd].valid) {
11252: int dup_fd = _dup(fd);
11253: if(dup_fd != -1) {
11254: REG16(AX) = dup_fd;
11255: msdos_file_handler_dup(dup_fd, fd, current_psp);
11256: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
11257: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 11258: } else {
11259: REG16(AX) = errno;
1.1.1.3 root 11260: m_CF = 1;
1.1 root 11261: }
11262: } else {
11263: REG16(AX) = 0x06;
1.1.1.3 root 11264: m_CF = 1;
1.1 root 11265: }
11266: }
11267:
11268: inline void msdos_int_21h_46h()
11269: {
11270: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11271: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11272: int dup_fd = REG16(CX);
11273: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 11274:
1.1.1.20 root 11275: if(REG16(BX) == REG16(CX)) {
11276: REG16(AX) = 0x06;
11277: m_CF = 1;
11278: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
11279: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
11280: _close(tmp_fd);
11281: msdos_file_handler_close(tmp_fd);
11282: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
11283: }
11284: if(_dup2(fd, dup_fd) != -1) {
11285: msdos_file_handler_dup(dup_fd, fd, current_psp);
11286: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
11287: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 11288: } else {
11289: REG16(AX) = errno;
1.1.1.3 root 11290: m_CF = 1;
1.1 root 11291: }
11292: } else {
11293: REG16(AX) = 0x06;
1.1.1.3 root 11294: m_CF = 1;
1.1 root 11295: }
11296: }
11297:
11298: inline void msdos_int_21h_47h(int lfn)
11299: {
11300: char path[MAX_PATH];
11301:
11302: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
1.1.1.45 root 11303: if(!lfn) {
11304: strcpy(path, msdos_short_path(path));
11305: }
1.1 root 11306: if(path[1] == ':') {
11307: // the returned path does not include a drive or the initial backslash
1.1.1.45 root 11308: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path + 3);
1.1 root 11309: } else {
1.1.1.45 root 11310: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path);
1.1 root 11311: }
11312: } else {
11313: REG16(AX) = errno;
1.1.1.3 root 11314: m_CF = 1;
1.1 root 11315: }
11316: }
11317:
11318: inline void msdos_int_21h_48h()
11319: {
1.1.1.19 root 11320: int seg, umb_linked;
1.1 root 11321:
1.1.1.8 root 11322: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 11323: // unlink umb not to allocate memory in umb
11324: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
11325: msdos_mem_unlink_umb();
11326: }
1.1.1.8 root 11327: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
11328: REG16(AX) = seg;
11329: } else {
11330: REG16(AX) = 0x08;
11331: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
11332: m_CF = 1;
11333: }
1.1.1.19 root 11334: if(umb_linked != 0) {
11335: msdos_mem_link_umb();
11336: }
1.1.1.8 root 11337: } else if((malloc_strategy & 0xf0) == 0x40) {
11338: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
11339: REG16(AX) = seg;
11340: } else {
11341: REG16(AX) = 0x08;
11342: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
11343: m_CF = 1;
11344: }
11345: } else if((malloc_strategy & 0xf0) == 0x80) {
11346: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
11347: REG16(AX) = seg;
11348: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
11349: REG16(AX) = seg;
11350: } else {
11351: REG16(AX) = 0x08;
11352: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
11353: m_CF = 1;
11354: }
1.1 root 11355: }
11356: }
11357:
11358: inline void msdos_int_21h_49h()
11359: {
1.1.1.14 root 11360: int mcb_seg = SREG(ES) - 1;
11361: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
11362:
11363: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11364: msdos_mem_free(SREG(ES));
11365: } else {
1.1.1.33 root 11366: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 11367: m_CF = 1;
11368: }
1.1 root 11369: }
11370:
11371: inline void msdos_int_21h_4ah()
11372: {
1.1.1.14 root 11373: int mcb_seg = SREG(ES) - 1;
11374: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 11375: int max_paragraphs;
11376:
1.1.1.14 root 11377: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11378: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
11379: REG16(AX) = 0x08;
11380: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
11381: m_CF = 1;
11382: }
11383: } else {
1.1.1.33 root 11384: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 11385: m_CF = 1;
1.1 root 11386: }
11387: }
11388:
11389: inline void msdos_int_21h_4bh()
11390: {
1.1.1.3 root 11391: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
11392: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 11393:
11394: switch(REG8(AL)) {
11395: case 0x00:
11396: case 0x01:
11397: if(msdos_process_exec(command, param, REG8(AL))) {
11398: REG16(AX) = 0x02;
1.1.1.3 root 11399: m_CF = 1;
1.1 root 11400: }
11401: break;
1.1.1.14 root 11402: case 0x03:
11403: {
11404: int fd;
11405: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
11406: REG16(AX) = 0x02;
11407: m_CF = 1;
11408: break;
11409: }
11410: int size = _read(fd, file_buffer, sizeof(file_buffer));
11411: _close(fd);
11412:
11413: UINT16 *overlay = (UINT16 *)param;
11414:
11415: // check exe header
11416: exe_header_t *header = (exe_header_t *)file_buffer;
11417: int header_size = 0;
11418: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
11419: header_size = header->header_size * 16;
11420: // relocation
11421: int start_seg = overlay[1];
11422: for(int i = 0; i < header->relocations; i++) {
11423: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
11424: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
11425: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
11426: }
11427: }
11428: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
11429: }
11430: break;
1.1.1.48 root 11431: case 0x04:
11432: // Load And Execute In Background (European MS-DOS 4.0 only)
11433: // case 0x05:
11434: // // DOS 5+ - Set Execution State
11435: case 0x80:
11436: // DR DOS v3.41 - Run Already-Loaded Kernel File
11437: case 0xf0:
11438: case 0xf1:
11439: // DIET v1.10+
1.1.1.43 root 11440: case 0xfd:
11441: case 0xfe:
11442: // unknown function called in FreeCOM
11443: REG16(AX) = 0x01;
11444: m_CF = 1;
11445: break;
1.1 root 11446: default:
1.1.1.22 root 11447: 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 11448: REG16(AX) = 0x01;
1.1.1.3 root 11449: m_CF = 1;
1.1 root 11450: break;
11451: }
11452: }
11453:
11454: inline void msdos_int_21h_4ch()
11455: {
11456: msdos_process_terminate(current_psp, REG8(AL), 1);
11457: }
11458:
11459: inline void msdos_int_21h_4dh()
11460: {
11461: REG16(AX) = retval;
11462: }
11463:
11464: inline void msdos_int_21h_4eh()
11465: {
11466: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 11467: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
11468: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.45 root 11469: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 11470: WIN32_FIND_DATA fd;
11471:
1.1.1.14 root 11472: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
11473: find->find_magic = FIND_MAGIC;
11474: find->dta_index = dtainfo - dtalist;
1.1 root 11475: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 11476: dtainfo->allowable_mask = REG8(CL);
11477: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 11478:
1.1.1.14 root 11479: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
11480: dtainfo->allowable_mask &= ~8;
1.1 root 11481: }
1.1.1.14 root 11482: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
11483: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 11484: !msdos_find_file_has_8dot3name(&fd)) {
11485: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11486: FindClose(dtainfo->find_handle);
11487: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11488: break;
11489: }
11490: }
11491: }
1.1.1.13 root 11492: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11493: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
11494: msdos_find_file_conv_local_time(&fd);
11495: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
11496: find->size = fd.nFileSizeLow;
1.1.1.13 root 11497: strcpy(find->name, msdos_short_name(&fd));
1.1 root 11498: REG16(AX) = 0;
1.1.1.14 root 11499: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11500: find->attrib = 8;
11501: find->size = 0;
11502: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11503: dtainfo->allowable_mask &= ~8;
1.1 root 11504: REG16(AX) = 0;
11505: } else {
11506: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 11507: m_CF = 1;
1.1 root 11508: }
11509: }
11510:
11511: inline void msdos_int_21h_4fh()
11512: {
11513: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 11514: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
11515: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 11516: WIN32_FIND_DATA fd;
11517:
1.1.1.14 root 11518: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
11519: REG16(AX) = 0x12;
11520: m_CF = 1;
11521: return;
11522: }
11523: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 11524: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
11525: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 11526: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 11527: !msdos_find_file_has_8dot3name(&fd)) {
11528: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11529: FindClose(dtainfo->find_handle);
11530: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11531: break;
11532: }
11533: }
11534: } else {
1.1.1.13 root 11535: FindClose(dtainfo->find_handle);
11536: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11537: }
11538: }
1.1.1.13 root 11539: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11540: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
11541: msdos_find_file_conv_local_time(&fd);
11542: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
11543: find->size = fd.nFileSizeLow;
1.1.1.13 root 11544: strcpy(find->name, msdos_short_name(&fd));
1.1 root 11545: REG16(AX) = 0;
1.1.1.14 root 11546: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11547: find->attrib = 8;
11548: find->size = 0;
11549: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11550: dtainfo->allowable_mask &= ~8;
1.1 root 11551: REG16(AX) = 0;
11552: } else {
11553: REG16(AX) = 0x12;
1.1.1.3 root 11554: m_CF = 1;
1.1 root 11555: }
11556: }
11557:
11558: inline void msdos_int_21h_50h()
11559: {
1.1.1.8 root 11560: if(current_psp != REG16(BX)) {
11561: process_t *process = msdos_process_info_get(current_psp);
11562: if(process != NULL) {
11563: process->psp = REG16(BX);
11564: }
11565: current_psp = REG16(BX);
1.1.1.23 root 11566: msdos_sda_update(current_psp);
1.1.1.8 root 11567: }
1.1 root 11568: }
11569:
11570: inline void msdos_int_21h_51h()
11571: {
11572: REG16(BX) = current_psp;
11573: }
11574:
11575: inline void msdos_int_21h_52h()
11576: {
1.1.1.25 root 11577: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 11578: i386_load_segment_descriptor(ES);
1.1.1.25 root 11579: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 11580: }
11581:
1.1.1.43 root 11582: inline void msdos_int_21h_53h()
11583: {
11584: dpb_t *dpb = (dpb_t *)(mem + SREG_BASE(ES) + REG16(BP));
11585: bpb_t *bpb = (bpb_t *)(mem + SREG_BASE(DS) + REG16(SI));
11586:
11587: dpb->bytes_per_sector = bpb->bytes_per_sector;
11588: dpb->highest_sector_num = bpb->sectors_per_track - 1;
11589: dpb->shift_count = 0;
11590: dpb->reserved_sectors = 0;
11591: dpb->fat_num = bpb->fat_num;
11592: dpb->root_entries = bpb->root_entries;
11593: dpb->first_data_sector = 0;
11594: if(bpb->sectors_per_cluster != 0) {
11595: dpb->highest_cluster_num = (UINT16)(((REG16(CX) == 0x4558 && bpb->total_sectors == 0) ? bpb->ext_total_sectors : bpb->total_sectors) / bpb->sectors_per_cluster + 1);
11596: } else {
11597: dpb->highest_cluster_num = 0;
11598: }
11599: dpb->sectors_per_fat = (REG16(CX) == 0x4558 && bpb->sectors_per_fat == 0) ? bpb->ext_sectors_per_fat : bpb->sectors_per_fat;
11600: dpb->first_dir_sector = 0;
11601: dpb->device_driver_header = 0;
11602: dpb->media_type = bpb->media_type;
11603: dpb->drive_accessed = 0;
11604: dpb->next_dpb_ofs = 0xffff;
11605: dpb->next_dpb_seg = 0xffff;
11606: dpb->first_free_cluster = 0;
11607: dpb->free_clusters = 0xffff;
11608: }
11609:
1.1 root 11610: inline void msdos_int_21h_54h()
11611: {
11612: process_t *process = msdos_process_info_get(current_psp);
11613:
11614: REG8(AL) = process->verify;
11615: }
11616:
11617: inline void msdos_int_21h_55h()
11618: {
11619: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
11620:
11621: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
11622: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
11623: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
11624: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
11625: psp->parent_psp = current_psp;
11626: }
11627:
11628: inline void msdos_int_21h_56h(int lfn)
11629: {
11630: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 11631: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
11632: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 11633:
11634: if(rename(src, dst)) {
11635: REG16(AX) = errno;
1.1.1.3 root 11636: m_CF = 1;
1.1 root 11637: }
11638: }
11639:
11640: inline void msdos_int_21h_57h()
11641: {
11642: FILETIME time, local;
1.1.1.14 root 11643: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 11644: HANDLE hHandle;
1.1 root 11645:
1.1.1.21 root 11646: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 11647: REG16(AX) = (UINT16)GetLastError();
11648: m_CF = 1;
11649: return;
11650: }
11651: ctime = atime = mtime = NULL;
11652:
1.1 root 11653: switch(REG8(AL)) {
11654: case 0x00:
1.1.1.6 root 11655: case 0x01:
1.1.1.14 root 11656: mtime = &time;
1.1.1.6 root 11657: break;
11658: case 0x04:
11659: case 0x05:
1.1.1.14 root 11660: atime = &time;
1.1 root 11661: break;
1.1.1.6 root 11662: case 0x06:
11663: case 0x07:
1.1.1.14 root 11664: ctime = &time;
11665: break;
11666: default:
1.1.1.22 root 11667: 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 11668: REG16(AX) = 0x01;
11669: m_CF = 1;
11670: return;
11671: }
11672: if(REG8(AL) & 1) {
1.1 root 11673: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
11674: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 11675: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 11676: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11677: m_CF = 1;
1.1 root 11678: }
1.1.1.14 root 11679: } else {
1.1.1.21 root 11680: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 11681: // assume a device and use the current time
11682: GetSystemTimeAsFileTime(&time);
11683: }
11684: FileTimeToLocalFileTime(&time, &local);
11685: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 11686: }
11687: }
11688:
11689: inline void msdos_int_21h_58h()
11690: {
11691: switch(REG8(AL)) {
11692: case 0x00:
1.1.1.7 root 11693: REG16(AX) = malloc_strategy;
11694: break;
11695: case 0x01:
1.1.1.24 root 11696: // switch(REG16(BX)) {
11697: switch(REG8(BL)) {
1.1.1.7 root 11698: case 0x0000:
11699: case 0x0001:
11700: case 0x0002:
11701: case 0x0040:
11702: case 0x0041:
11703: case 0x0042:
11704: case 0x0080:
11705: case 0x0081:
11706: case 0x0082:
11707: malloc_strategy = REG16(BX);
1.1.1.23 root 11708: msdos_sda_update(current_psp);
1.1.1.7 root 11709: break;
11710: default:
1.1.1.22 root 11711: 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 11712: REG16(AX) = 0x01;
11713: m_CF = 1;
11714: break;
11715: }
11716: break;
11717: case 0x02:
1.1.1.19 root 11718: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 11719: break;
11720: case 0x03:
1.1.1.24 root 11721: // switch(REG16(BX)) {
11722: switch(REG8(BL)) {
1.1.1.7 root 11723: case 0x0000:
1.1.1.19 root 11724: msdos_mem_unlink_umb();
11725: break;
1.1.1.7 root 11726: case 0x0001:
1.1.1.19 root 11727: msdos_mem_link_umb();
1.1.1.7 root 11728: break;
11729: default:
1.1.1.22 root 11730: 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 11731: REG16(AX) = 0x01;
11732: m_CF = 1;
11733: break;
11734: }
1.1 root 11735: break;
11736: default:
1.1.1.22 root 11737: 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 11738: REG16(AX) = 0x01;
1.1.1.3 root 11739: m_CF = 1;
1.1 root 11740: break;
11741: }
11742: }
11743:
11744: inline void msdos_int_21h_59h()
11745: {
1.1.1.47 root 11746: if(REG16(BX) == 0x0000) {
11747: sda_t *sda = (sda_t *)(mem + SDA_TOP);
11748:
11749: REG16(AX) = sda->extended_error_code;
11750: REG8(BH) = sda->error_class;
11751: REG8(BL) = sda->suggested_action;
11752: REG8(CH) = sda->locus_of_last_error;
11753: // XXX: GW-BASIC 3.23 invites the registers contents of CL, DX, SI, DI, DS, and ES are not destroyed
11754: if(sda->int21h_5d0ah_called != 0) {
11755: REG8(CL) = sda->int21h_5d0ah_cl;
11756: REG16(DX) = sda->int21h_5d0ah_dx;
11757: // REG16(SI) = sda->int21h_5d0ah_si;
11758: REG16(DI) = sda->last_error_pointer.w.l;
11759: // SREG(DS) = sda->int21h_5d0ah_ds;
11760: // i386_load_segment_descriptor(DS);
11761: SREG(ES) = sda->last_error_pointer.w.h;
11762: i386_load_segment_descriptor(ES);
11763: }
11764: sda->int21h_5d0ah_called = 0;
11765: // } else if(REG16(BX) == 0x0001) {
11766: // // European MS-DOS 4.0 - Get Hard Error Information
11767: } else {
11768: 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));
11769: REG16(AX) = 0x01;
11770: m_CF = 1;
11771: }
1.1 root 11772: }
11773:
11774: inline void msdos_int_21h_5ah()
11775: {
1.1.1.3 root 11776: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 11777: int len = strlen(path);
11778: char tmp[MAX_PATH];
11779:
11780: if(GetTempFileName(path, "TMP", 0, tmp)) {
11781: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11782:
11783: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11784: REG16(AX) = fd;
11785: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11786: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11787:
11788: strcpy(path, tmp);
11789: int dx = REG16(DX) + len;
1.1.1.3 root 11790: int ds = SREG(DS);
1.1 root 11791: while(dx > 0xffff) {
11792: dx -= 0x10;
11793: ds++;
11794: }
11795: REG16(DX) = dx;
1.1.1.3 root 11796: SREG(DS) = ds;
11797: i386_load_segment_descriptor(DS);
1.1 root 11798: } else {
11799: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11800: m_CF = 1;
1.1 root 11801: }
11802: }
11803:
11804: inline void msdos_int_21h_5bh()
11805: {
1.1.1.45 root 11806: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 11807:
1.1.1.45 root 11808: // if(msdos_is_existing_file(path)) {
11809: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 11810: // already exists
11811: REG16(AX) = 0x50;
1.1.1.3 root 11812: m_CF = 1;
1.1 root 11813: } else {
11814: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11815:
11816: if(fd != -1) {
11817: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11818: REG16(AX) = fd;
11819: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11820: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11821: } else {
11822: REG16(AX) = errno;
1.1.1.3 root 11823: m_CF = 1;
1.1 root 11824: }
11825: }
11826: }
11827:
11828: inline void msdos_int_21h_5ch()
11829: {
11830: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11831: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 11832:
1.1.1.20 root 11833: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 11834: if(REG8(AL) == 0 || REG8(AL) == 1) {
1.1.1.35 root 11835: static const int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 11836: UINT32 pos = _tell(fd);
11837: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
11838: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 11839: REG16(AX) = errno;
1.1.1.3 root 11840: m_CF = 1;
1.1 root 11841: }
1.1.1.20 root 11842: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 11843:
1.1 root 11844: // some seconds may be passed in _locking()
1.1.1.35 root 11845: REQUEST_HARDWRE_UPDATE();
1.1 root 11846: } else {
11847: REG16(AX) = 0x01;
1.1.1.3 root 11848: m_CF = 1;
1.1 root 11849: }
11850: } else {
11851: REG16(AX) = 0x06;
1.1.1.3 root 11852: m_CF = 1;
1.1 root 11853: }
11854: }
11855:
1.1.1.22 root 11856: inline void msdos_int_21h_5dh()
11857: {
11858: switch(REG8(AL)) {
1.1.1.45 root 11859: case 0x00:
11860: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x12) == 0x0000) {
11861: // current system
11862: static bool reenter = false;
11863: if(!reenter) {
11864: UINT32 offset = SREG_BASE(DS) + REG16(DX);
11865: REG16(AX) = *(UINT16 *)(mem + offset + 0x00);
11866: REG16(BX) = *(UINT16 *)(mem + offset + 0x02);
11867: REG16(CX) = *(UINT16 *)(mem + offset + 0x04);
11868: REG16(DX) = *(UINT16 *)(mem + offset + 0x06);
11869: REG16(SI) = *(UINT16 *)(mem + offset + 0x08);
11870: REG16(DI) = *(UINT16 *)(mem + offset + 0x0a);
11871: SREG(DS) = *(UINT16 *)(mem + offset + 0x0c);
11872: SREG(ES) = *(UINT16 *)(mem + offset + 0x0e);
11873: i386_load_segment_descriptor(DS);
11874: i386_load_segment_descriptor(ES);
11875: reenter = true;
11876: try {
11877: msdos_syscall(0x21);
11878: } catch(...) {
11879: }
11880: reenter = false;
11881: }
11882: } else {
11883: REG16(AX) = 0x49; // network software not installed
11884: m_CF = 1;
11885: }
11886: break;
1.1.1.22 root 11887: case 0x06: // get address of dos swappable data area
1.1.1.23 root 11888: SREG(DS) = (SDA_TOP >> 4);
11889: i386_load_segment_descriptor(DS);
11890: REG16(SI) = offsetof(sda_t, crit_error_flag);
11891: REG16(CX) = 0x80;
11892: REG16(DX) = 0x1a;
11893: break;
1.1.1.45 root 11894: case 0x07: // get redirected printer mode
11895: case 0x08: // set redirected printer mode
11896: case 0x09: // flush redirected printer output
11897: REG16(AX) = 0x49; // network software not installed
11898: m_CF = 1;
11899: break;
1.1.1.43 root 11900: case 0x0a: // set extended error information
11901: {
11902: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1.1.1.47 root 11903: sda->int21h_5d0ah_called = 1;
1.1.1.43 root 11904: sda->extended_error_code = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00); // AX
1.1.1.47 root 11905: // XXX: which one is correct ???
11906: #if 1
11907: // Ralf Brown's Interrupt List and DR-DOS System and Programmer's Guide
1.1.1.43 root 11908: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BL
11909: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BH
1.1.1.47 root 11910: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CL
1.1.1.43 root 11911: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CH
1.1.1.47 root 11912: #else
11913: // PC DOS 7 Technical Update
11914: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BH
11915: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BL
11916: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CH
11917: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CL
11918: #endif
11919: sda->int21h_5d0ah_dx = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06); // DX
11920: // sda->int21h_5d0ah_si = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08); // SI
1.1.1.43 root 11921: sda->last_error_pointer.w.l = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a); // DI
1.1.1.47 root 11922: // sda->int21h_5d0ah_ds = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c); // DS
1.1.1.43 root 11923: sda->last_error_pointer.w.h = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // ES
11924: }
11925: break;
1.1.1.23 root 11926: case 0x0b: // get dos swappable data areas
1.1.1.22 root 11927: REG16(AX) = 0x01;
11928: m_CF = 1;
11929: break;
11930: default:
11931: 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));
11932: REG16(AX) = 0x01;
11933: m_CF = 1;
11934: break;
11935: }
11936: }
11937:
1.1.1.42 root 11938: inline void msdos_int_21h_5eh()
11939: {
11940: switch(REG8(AL)) {
11941: case 0x00:
11942: {
11943: char name[256] = {0};
11944: DWORD dwSize = 256;
11945:
11946: if(GetComputerName(name, &dwSize)) {
11947: char *dest = (char *)(mem + SREG_BASE(DS) + REG16(DX));
11948: for(int i = 0; i < 15; i++) {
11949: dest[i] = (i < strlen(name)) ? name[i] : ' ';
11950: }
11951: dest[15] = '\0';
11952: REG8(CH) = 0x01; // nonzero valid
11953: REG8(CL) = 0x01; // NetBIOS number for machine name ???
11954: } else {
11955: REG16(AX) = 0x01;
11956: m_CF = 1;
11957: }
11958: }
11959: break;
11960: default:
1.1.1.45 root 11961: // 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));
11962: // REG16(AX) = 0x01;
11963: REG16(AX) = 0x49; // network software not installed
1.1.1.42 root 11964: m_CF = 1;
11965: break;
11966: }
11967: }
11968:
1.1.1.30 root 11969: inline void msdos_int_21h_5fh()
11970: {
11971: switch(REG8(AL)) {
1.1.1.42 root 11972: case 0x05:
1.1.1.44 root 11973: REG16(BP) = 0;
11974: for(int i = 0; i < 26; i++) {
11975: if(msdos_is_remote_drive(i)) {
11976: REG16(BP)++;
1.1.1.42 root 11977: }
11978: }
1.1.1.30 root 11979: case 0x02:
1.1.1.44 root 11980: for(int i = 0, index = 0; i < 26; i++) {
11981: if(msdos_is_remote_drive(i)) {
11982: if(index == REG16(BX)) {
11983: char volume[] = "A:";
1.1.1.30 root 11984: volume[0] = 'A' + i;
1.1.1.44 root 11985: DWORD dwSize = 128;
11986: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
11987: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
11988: REG8(BH) = 0x00; // valid
11989: REG8(BL) = 0x04; // disk drive
11990: REG16(CX) = 0x00; // LANtastic
11991: return;
1.1.1.30 root 11992: }
1.1.1.44 root 11993: index++;
1.1.1.30 root 11994: }
11995: }
11996: REG16(AX) = 0x12; // no more files
11997: m_CF = 1;
11998: break;
1.1.1.44 root 11999: case 0x07:
12000: if(msdos_is_valid_drive(REG8(DL))) {
12001: msdos_cds_update(REG8(DL));
12002: } else {
12003: REG16(AX) = 0x0f; // invalid drive
12004: m_CF = 1;
12005: }
12006: break;
12007: case 0x08:
12008: if(msdos_is_valid_drive(REG8(DL))) {
12009: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * REG8(DL));
12010: cds->drive_attrib = 0x0000;
12011: } else {
12012: REG16(AX) = 0x0f; // invalid drive
12013: m_CF = 1;
12014: }
12015: break;
1.1.1.30 root 12016: default:
1.1.1.45 root 12017: // 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));
12018: // REG16(AX) = 0x01;
12019: REG16(AX) = 0x49; // network software not installed
1.1.1.30 root 12020: m_CF = 1;
12021: break;
12022: }
12023: }
12024:
1.1 root 12025: inline void msdos_int_21h_60h(int lfn)
12026: {
1.1.1.45 root 12027: char full[MAX_PATH];
12028: const char *path = NULL;
1.1.1.14 root 12029:
1.1 root 12030: if(lfn) {
1.1.1.14 root 12031: char *name;
12032: *full = '\0';
1.1.1.3 root 12033: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 12034: switch(REG8(CL)) {
12035: case 1:
12036: GetShortPathName(full, full, MAX_PATH);
12037: my_strupr(full);
12038: break;
12039: case 2:
12040: GetLongPathName(full, full, MAX_PATH);
12041: break;
12042: }
12043: path = full;
12044: } else {
12045: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
12046: }
12047: if(*path != '\0') {
12048: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 12049: } else {
1.1.1.14 root 12050: REG16(AX) = (UINT16)GetLastError();
12051: m_CF = 1;
1.1 root 12052: }
12053: }
12054:
12055: inline void msdos_int_21h_61h()
12056: {
12057: REG8(AL) = 0;
12058: }
12059:
12060: inline void msdos_int_21h_62h()
12061: {
12062: REG16(BX) = current_psp;
12063: }
12064:
12065: inline void msdos_int_21h_63h()
12066: {
12067: switch(REG8(AL)) {
12068: case 0x00:
1.1.1.3 root 12069: SREG(DS) = (DBCS_TABLE >> 4);
12070: i386_load_segment_descriptor(DS);
1.1 root 12071: REG16(SI) = (DBCS_TABLE & 0x0f);
12072: REG8(AL) = 0x00;
12073: break;
1.1.1.22 root 12074: case 0x01: // set korean input mode
12075: case 0x02: // get korean input mode
12076: REG8(AL) = 0xff; // not supported
12077: break;
1.1 root 12078: default:
1.1.1.22 root 12079: 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 12080: REG16(AX) = 0x01;
1.1.1.3 root 12081: m_CF = 1;
1.1 root 12082: break;
12083: }
12084: }
12085:
1.1.1.25 root 12086: UINT16 get_extended_country_info(UINT8 func)
1.1 root 12087: {
1.1.1.25 root 12088: switch(func) {
1.1.1.17 root 12089: case 0x01:
12090: if(REG16(CX) >= 5) {
1.1.1.19 root 12091: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 12092: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
12093: REG16(CX) = sizeof(data);
12094: ZeroMemory(data, sizeof(data));
12095: data[0] = 0x01;
12096: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 12097: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 12098: *(UINT16 *)(data + 5) = active_code_page;
12099: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 12100: // REG16(AX) = active_code_page;
1.1.1.17 root 12101: } else {
1.1.1.25 root 12102: return(0x08); // insufficient memory
1.1.1.17 root 12103: }
12104: break;
12105: case 0x02:
12106: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
12107: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
12108: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 12109: // REG16(AX) = active_code_page;
1.1.1.17 root 12110: REG16(CX) = 0x05;
12111: break;
1.1.1.23 root 12112: case 0x03:
12113: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
12114: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
12115: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 12116: // REG16(AX) = active_code_page;
1.1.1.23 root 12117: REG16(CX) = 0x05;
12118: break;
1.1.1.17 root 12119: case 0x04:
12120: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
12121: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
12122: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 12123: // REG16(AX) = active_code_page;
1.1.1.17 root 12124: REG16(CX) = 0x05;
12125: break;
12126: case 0x05:
12127: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
12128: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
12129: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 12130: // REG16(AX) = active_code_page;
1.1.1.17 root 12131: REG16(CX) = 0x05;
12132: break;
12133: case 0x06:
12134: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
12135: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
12136: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 12137: // REG16(AX) = active_code_page;
1.1.1.17 root 12138: REG16(CX) = 0x05;
12139: break;
1.1 root 12140: case 0x07:
1.1.1.3 root 12141: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
12142: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
12143: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 12144: // REG16(AX) = active_code_page;
1.1 root 12145: REG16(CX) = 0x05;
12146: break;
1.1.1.25 root 12147: default:
12148: return(0x01); // function number invalid
12149: }
12150: return(0x00);
12151: }
12152:
12153: inline void msdos_int_21h_65h()
12154: {
12155: char tmp[0x10000];
12156:
12157: switch(REG8(AL)) {
1.1.1.43 root 12158: case 0x00:
12159: if(REG16(CX) >= 7) {
12160: set_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), REG16(CX) - 7);
12161: REG16(AX) = system_code_page;
12162: } else {
12163: REG16(AX) = 0x0c;
12164: m_CF = 1;
12165: }
12166: break;
1.1.1.25 root 12167: case 0x01:
12168: case 0x02:
12169: case 0x03:
12170: case 0x04:
12171: case 0x05:
12172: case 0x06:
12173: case 0x07:
12174: {
12175: UINT16 result = get_extended_country_info(REG8(AL));
12176: if(result) {
12177: REG16(AX) = result;
12178: m_CF = 1;
12179: } else {
12180: REG16(AX) = active_code_page; // FIXME: is this correct???
12181: }
12182: }
12183: break;
1.1 root 12184: case 0x20:
1.1.1.25 root 12185: case 0xa0:
1.1.1.19 root 12186: memset(tmp, 0, sizeof(tmp));
12187: tmp[0] = REG8(DL);
1.1 root 12188: my_strupr(tmp);
12189: REG8(DL) = tmp[0];
12190: break;
12191: case 0x21:
1.1.1.25 root 12192: case 0xa1:
1.1 root 12193: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 12194: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 12195: my_strupr(tmp);
1.1.1.3 root 12196: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 12197: break;
12198: case 0x22:
1.1.1.25 root 12199: case 0xa2:
1.1.1.3 root 12200: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 12201: break;
1.1.1.25 root 12202: case 0x23:
12203: // FIXME: need to check multi-byte (kanji) charactre?
1.1.1.45 root 12204: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
1.1.1.25 root 12205: // 826dh/828eh: multi-byte (kanji) N and n
1.1.1.45 root 12206: REG16(AX) = 0x00;
12207: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
12208: // 8278h/8299h: multi-byte (kanji) Y and y
1.1.1.25 root 12209: REG16(AX) = 0x01;
12210: } else {
12211: REG16(AX) = 0x02;
12212: }
12213: break;
1.1 root 12214: default:
1.1.1.22 root 12215: 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 12216: REG16(AX) = 0x01;
1.1.1.3 root 12217: m_CF = 1;
1.1 root 12218: break;
12219: }
12220: }
12221:
12222: inline void msdos_int_21h_66h()
12223: {
12224: switch(REG8(AL)) {
12225: case 0x01:
12226: REG16(BX) = active_code_page;
12227: REG16(DX) = system_code_page;
12228: break;
12229: case 0x02:
12230: if(active_code_page == REG16(BX)) {
12231: REG16(AX) = 0xeb41;
12232: } else if(_setmbcp(REG16(BX)) == 0) {
12233: active_code_page = REG16(BX);
1.1.1.17 root 12234: msdos_nls_tables_update();
1.1 root 12235: REG16(AX) = 0xeb41;
1.1.1.32 root 12236: SetConsoleCP(active_code_page);
12237: SetConsoleOutputCP(active_code_page);
1.1 root 12238: } else {
12239: REG16(AX) = 0x25;
1.1.1.3 root 12240: m_CF = 1;
1.1 root 12241: }
12242: break;
12243: default:
1.1.1.22 root 12244: 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 12245: REG16(AX) = 0x01;
1.1.1.3 root 12246: m_CF = 1;
1.1 root 12247: break;
12248: }
12249: }
12250:
12251: inline void msdos_int_21h_67h()
12252: {
12253: process_t *process = msdos_process_info_get(current_psp);
12254:
12255: if(REG16(BX) <= MAX_FILES) {
12256: process->max_files = max(REG16(BX), 20);
12257: } else {
12258: REG16(AX) = 0x08;
1.1.1.3 root 12259: m_CF = 1;
1.1 root 12260: }
12261: }
12262:
12263: inline void msdos_int_21h_68h()
12264: {
12265: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 12266: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 12267:
1.1.1.20 root 12268: if(fd < process->max_files && file_handler[fd].valid) {
12269: // fflush(_fdopen(fd, ""));
1.1 root 12270: } else {
12271: REG16(AX) = 0x06;
1.1.1.3 root 12272: m_CF = 1;
1.1 root 12273: }
12274: }
12275:
12276: inline void msdos_int_21h_69h()
12277: {
1.1.1.3 root 12278: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12279: char path[] = "A:\\";
12280: char volume_label[MAX_PATH];
12281: DWORD serial_number = 0;
12282: char file_system[MAX_PATH];
12283:
12284: if(REG8(BL) == 0) {
12285: path[0] = 'A' + _getdrive() - 1;
12286: } else {
12287: path[0] = 'A' + REG8(BL) - 1;
12288: }
12289:
12290: switch(REG8(AL)) {
12291: case 0x00:
12292: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
12293: info->info_level = 0;
12294: info->serial_number = serial_number;
12295: memset(info->volume_label, 0x20, 11);
12296: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
12297: memset(info->file_system, 0x20, 8);
12298: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
12299: } else {
12300: REG16(AX) = errno;
1.1.1.3 root 12301: m_CF = 1;
1.1 root 12302: }
12303: break;
12304: case 0x01:
12305: REG16(AX) = 0x03;
1.1.1.3 root 12306: m_CF = 1;
1.1.1.45 root 12307: break;
12308: default:
12309: 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));
12310: REG16(AX) = 0x01;
12311: m_CF = 1;
12312: break;
1.1 root 12313: }
12314: }
12315:
12316: inline void msdos_int_21h_6ah()
12317: {
12318: REG8(AH) = 0x68;
12319: msdos_int_21h_68h();
12320: }
12321:
12322: inline void msdos_int_21h_6bh()
12323: {
1.1.1.45 root 12324: REG8(AL) = 0x00;
1.1 root 12325: }
12326:
12327: inline void msdos_int_21h_6ch(int lfn)
12328: {
1.1.1.45 root 12329: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 12330: int mode = REG8(BL) & 0x03;
12331:
12332: if(mode < 0x03) {
1.1.1.29 root 12333: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 12334: // file exists
12335: if(REG8(DL) & 1) {
1.1.1.37 root 12336: int fd = -1;
12337: int sio_port = 0;
12338: int lpt_port = 0;
1.1 root 12339:
1.1.1.45 root 12340: if(msdos_is_device_path(path)) {
12341: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
1.1.1.11 root 12342: } else {
1.1.1.13 root 12343: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 12344: }
1.1 root 12345: if(fd != -1) {
12346: REG16(AX) = fd;
12347: REG16(CX) = 1;
1.1.1.45 root 12348: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 12349: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 12350: } else {
12351: REG16(AX) = errno;
1.1.1.3 root 12352: m_CF = 1;
1.1 root 12353: }
12354: } else if(REG8(DL) & 2) {
12355: int attr = GetFileAttributes(path);
1.1.1.37 root 12356: int fd = -1;
12357: int sio_port = 0;
12358: int lpt_port = 0;
1.1 root 12359:
1.1.1.45 root 12360: if(msdos_is_device_path(path)) {
12361: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port);
1.1 root 12362: } else {
12363: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
12364: }
12365: if(fd != -1) {
12366: if(attr == -1) {
12367: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
12368: }
12369: SetFileAttributes(path, attr);
12370: REG16(AX) = fd;
12371: REG16(CX) = 3;
1.1.1.45 root 12372: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port);
1.1.1.20 root 12373: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 12374: } else {
12375: REG16(AX) = errno;
1.1.1.3 root 12376: m_CF = 1;
1.1 root 12377: }
12378: } else {
12379: REG16(AX) = 0x50;
1.1.1.3 root 12380: m_CF = 1;
1.1 root 12381: }
12382: } else {
12383: // file not exists
12384: if(REG8(DL) & 0x10) {
12385: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
12386:
12387: if(fd != -1) {
12388: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
12389: REG16(AX) = fd;
12390: REG16(CX) = 2;
12391: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 12392: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 12393: } else {
12394: REG16(AX) = errno;
1.1.1.3 root 12395: m_CF = 1;
1.1 root 12396: }
12397: } else {
12398: REG16(AX) = 0x02;
1.1.1.3 root 12399: m_CF = 1;
1.1 root 12400: }
12401: }
12402: } else {
12403: REG16(AX) = 0x0c;
1.1.1.3 root 12404: m_CF = 1;
1.1 root 12405: }
12406: }
12407:
1.1.1.43 root 12408: inline void msdos_int_21h_70h()
12409: {
12410: switch(REG8(AL)) {
1.1.1.48 root 12411: case 0x00: // get ??? info
12412: case 0x01: // set above info
12413: // 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));
12414: REG16(AX) = 0x7000;
12415: m_CF = 1;
12416: break;
12417: case 0x02: // set general internationalization info
1.1.1.43 root 12418: if(REG16(CX) >= 7) {
12419: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
12420: msdos_nls_tables_update();
12421: set_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(SI) + 7), REG16(CX) - 7);
12422: REG16(AX) = system_code_page;
12423: } else {
12424: REG16(AX) = 0x0c;
12425: m_CF = 1;
12426: }
12427: break;
12428: default:
12429: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 12430: REG16(AX) = 0x7000;
1.1.1.43 root 12431: m_CF = 1;
12432: break;
12433: }
12434: }
12435:
1.1 root 12436: inline void msdos_int_21h_710dh()
12437: {
12438: // reset drive
12439: }
12440:
1.1.1.48 root 12441: inline void msdos_int_21h_7141h()
1.1.1.17 root 12442: {
12443: if(REG16(SI) == 0) {
1.1.1.48 root 12444: msdos_int_21h_41h(1);
1.1.1.17 root 12445: return;
12446: }
12447: if(REG16(SI) != 1) {
12448: REG16(AX) = 5;
12449: m_CF = 1;
12450: }
12451: /* wild card and matching attributes... */
12452: char tmp[MAX_PATH * 2];
12453: // copy search pathname (and quick check overrun)
12454: ZeroMemory(tmp, sizeof(tmp));
12455: tmp[MAX_PATH - 1] = '\0';
12456: tmp[MAX_PATH] = 1;
12457: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
12458:
12459: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
12460: REG16(AX) = 1;
12461: m_CF = 1;
12462: return;
12463: }
12464: for(char *s = tmp; *s; ++s) {
12465: if(*s == '/') {
12466: *s = '\\';
12467: }
12468: }
12469: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
12470: if(tmp_name) {
12471: ++tmp_name;
12472: } else {
12473: tmp_name = strchr(tmp, ':');
12474: tmp_name = tmp_name ? tmp_name + 1 : tmp;
12475: }
12476:
12477: WIN32_FIND_DATAA fd;
12478: HANDLE fh = FindFirstFileA(tmp, &fd);
12479: if(fh == INVALID_HANDLE_VALUE) {
12480: REG16(AX) = 2;
12481: m_CF = 1;
12482: return;
12483: }
12484: do {
12485: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
12486: strcpy(tmp_name, fd.cFileName);
1.1.1.48 root 12487: if(remove(msdos_trimmed_path(tmp, 1))) {
1.1.1.17 root 12488: REG16(AX) = 5;
12489: m_CF = 1;
12490: break;
12491: }
12492: }
12493: } while(FindNextFileA(fh, &fd));
12494: if(!m_CF) {
12495: if(GetLastError() != ERROR_NO_MORE_FILES) {
12496: m_CF = 1;
12497: REG16(AX) = 2;
12498: }
12499: }
12500: FindClose(fh);
12501: }
12502:
1.1 root 12503: inline void msdos_int_21h_714eh()
12504: {
12505: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 12506: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
12507: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12508: WIN32_FIND_DATA fd;
12509:
1.1.1.13 root 12510: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
12511: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12512: FindClose(dtainfo->find_handle);
12513: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12514: }
12515: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 12516: dtainfo->allowable_mask = REG8(CL);
12517: dtainfo->required_mask = REG8(CH);
12518: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 12519:
1.1.1.14 root 12520: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
12521: dtainfo->allowable_mask &= ~8;
1.1 root 12522: }
1.1.1.14 root 12523: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
12524: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 12525: if(!FindNextFile(dtainfo->find_handle, &fd)) {
12526: FindClose(dtainfo->find_handle);
12527: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12528: break;
12529: }
12530: }
12531: }
1.1.1.13 root 12532: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 12533: find->attrib = fd.dwFileAttributes;
12534: msdos_find_file_conv_local_time(&fd);
12535: if(REG16(SI) == 0) {
12536: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
12537: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
12538: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
12539: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
12540: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
12541: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
12542: } else {
12543: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
12544: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
12545: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
12546: }
12547: find->size_hi = fd.nFileSizeHigh;
12548: find->size_lo = fd.nFileSizeLow;
12549: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 12550: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 12551: REG16(AX) = dtainfo - dtalist + 1;
12552: } else if(dtainfo->allowable_mask & 8) {
1.1 root 12553: // volume label
12554: find->attrib = 8;
12555: find->size_hi = find->size_lo = 0;
12556: strcpy(find->full_name, process->volume_label);
12557: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 12558: dtainfo->allowable_mask &= ~8;
12559: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 12560: } else {
12561: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 12562: m_CF = 1;
1.1 root 12563: }
12564: }
12565:
12566: inline void msdos_int_21h_714fh()
12567: {
12568: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 12569: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 12570: WIN32_FIND_DATA fd;
12571:
1.1.1.14 root 12572: if(REG16(BX) - 1u >= MAX_DTAINFO) {
12573: REG16(AX) = 6;
1.1.1.13 root 12574: m_CF = 1;
12575: return;
12576: }
1.1.1.14 root 12577: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 12578: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12579: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 12580: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 12581: if(!FindNextFile(dtainfo->find_handle, &fd)) {
12582: FindClose(dtainfo->find_handle);
12583: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12584: break;
12585: }
12586: }
12587: } else {
1.1.1.13 root 12588: FindClose(dtainfo->find_handle);
12589: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12590: }
12591: }
1.1.1.13 root 12592: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 12593: find->attrib = fd.dwFileAttributes;
12594: msdos_find_file_conv_local_time(&fd);
12595: if(REG16(SI) == 0) {
12596: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
12597: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
12598: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
12599: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
12600: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
12601: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
12602: } else {
12603: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
12604: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
12605: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
12606: }
12607: find->size_hi = fd.nFileSizeHigh;
12608: find->size_lo = fd.nFileSizeLow;
12609: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 12610: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 12611: } else if(dtainfo->allowable_mask & 8) {
1.1 root 12612: // volume label
12613: find->attrib = 8;
12614: find->size_hi = find->size_lo = 0;
12615: strcpy(find->full_name, process->volume_label);
12616: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 12617: dtainfo->allowable_mask &= ~8;
1.1 root 12618: } else {
12619: REG16(AX) = 0x12;
1.1.1.3 root 12620: m_CF = 1;
1.1 root 12621: }
12622: }
12623:
12624: inline void msdos_int_21h_71a0h()
12625: {
12626: DWORD max_component_len, file_sys_flag;
12627:
1.1.1.14 root 12628: 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))) {
12629: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
12630: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 12631: REG16(CX) = (UINT16)max_component_len; // 255
12632: REG16(DX) = (UINT16)max_component_len + 5; // 260
12633: } else {
12634: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12635: m_CF = 1;
1.1 root 12636: }
12637: }
12638:
12639: inline void msdos_int_21h_71a1h()
12640: {
1.1.1.14 root 12641: if(REG16(BX) - 1u >= MAX_DTAINFO) {
12642: REG16(AX) = 6;
1.1.1.13 root 12643: m_CF = 1;
12644: return;
12645: }
1.1.1.14 root 12646: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 12647: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12648: FindClose(dtainfo->find_handle);
12649: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12650: }
12651: }
12652:
12653: inline void msdos_int_21h_71a6h()
12654: {
12655: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 12656: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12657:
1.1.1.3 root 12658: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12659: struct _stat64 status;
12660: DWORD serial_number = 0;
12661:
1.1.1.20 root 12662: if(fd < process->max_files && file_handler[fd].valid) {
12663: if(_fstat64(fd, &status) == 0) {
12664: if(file_handler[fd].path[1] == ':') {
1.1 root 12665: // NOTE: we need to consider the network file path "\\host\share\"
12666: char volume[] = "A:\\";
1.1.1.20 root 12667: volume[0] = file_handler[fd].path[1];
1.1 root 12668: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
12669: }
1.1.1.20 root 12670: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 12671: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
12672: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
12673: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
12674: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
12675: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
12676: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
12677: *(UINT32 *)(buffer + 0x1c) = serial_number;
12678: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
12679: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
12680: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 12681: // this is dummy id and it will be changed when it is reopened...
1.1 root 12682: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 12683: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 12684: } else {
12685: REG16(AX) = errno;
1.1.1.3 root 12686: m_CF = 1;
1.1 root 12687: }
12688: } else {
12689: REG16(AX) = 0x06;
1.1.1.3 root 12690: m_CF = 1;
1.1 root 12691: }
12692: }
12693:
12694: inline void msdos_int_21h_71a7h()
12695: {
12696: switch(REG8(BL)) {
12697: case 0x00:
1.1.1.3 root 12698: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 12699: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12700: m_CF = 1;
1.1 root 12701: }
12702: break;
12703: case 0x01:
12704: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 12705: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 12706: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12707: m_CF = 1;
1.1 root 12708: }
12709: break;
12710: default:
1.1.1.22 root 12711: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 12712: REG16(AX) = 0x7100;
1.1.1.3 root 12713: m_CF = 1;
1.1 root 12714: break;
12715: }
12716: }
12717:
12718: inline void msdos_int_21h_71a8h()
12719: {
12720: if(REG8(DH) == 0) {
12721: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 12722: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 12723: memset(fcb, 0x20, sizeof(fcb));
12724: int len = strlen(tmp);
1.1.1.21 root 12725: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 12726: if(tmp[i] == '.') {
12727: pos = 8;
12728: } else {
12729: if(msdos_lead_byte_check(tmp[i])) {
12730: fcb[pos++] = tmp[i++];
12731: }
12732: fcb[pos++] = tmp[i];
12733: }
12734: }
1.1.1.3 root 12735: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 12736: } else {
1.1.1.3 root 12737: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 12738: }
12739: }
12740:
1.1.1.22 root 12741: inline void msdos_int_21h_71aah()
12742: {
12743: char drv[] = "A:", path[MAX_PATH];
12744: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
12745:
12746: if(REG8(BL) == 0) {
12747: drv[0] = 'A' + _getdrive() - 1;
12748: } else {
12749: drv[0] = 'A' + REG8(BL) - 1;
12750: }
12751: switch(REG8(BH)) {
12752: case 0x00:
1.1.1.44 root 12753: if(msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12754: REG16(AX) = 0x0f; // invalid drive
12755: m_CF = 1;
12756: } else if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
12757: REG16(AX) = 0x03; // path not found
1.1.1.22 root 12758: m_CF = 1;
12759: }
12760: break;
12761: case 0x01:
1.1.1.44 root 12762: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12763: REG16(AX) = 0x0f; // invalid drive
12764: m_CF = 1;
12765: } else if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
1.1.1.22 root 12766: REG16(AX) = 0x0f; // invalid drive
12767: m_CF = 1;
12768: }
12769: break;
12770: case 0x02:
1.1.1.44 root 12771: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) {
12772: REG16(AX) = 0x0f; // invalid drive
12773: m_CF = 1;
12774: } else if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
1.1.1.22 root 12775: REG16(AX) = 0x0f; // invalid drive
12776: m_CF = 1;
12777: } else if(strncmp(path, "\\??\\", 4) != 0) {
12778: REG16(AX) = 0x0f; // invalid drive
12779: m_CF = 1;
12780: } else {
12781: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
12782: }
12783: break;
12784: default:
12785: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.48 root 12786: REG16(AX) = 0x7100;
1.1.1.22 root 12787: m_CF = 1;
12788: break;
12789: }
12790: }
12791:
1.1.1.14 root 12792: inline void msdos_int_21h_7300h()
12793: {
1.1.1.44 root 12794: REG8(AL) = REG8(CL);
12795: REG8(AH) = 0;
1.1.1.14 root 12796: }
12797:
12798: inline void msdos_int_21h_7302h()
12799: {
12800: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
12801: UINT16 seg, ofs;
12802:
12803: if(REG16(CX) < 0x3f) {
12804: REG8(AL) = 0x18;
12805: m_CF = 1;
12806: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
12807: REG8(AL) = 0xff;
12808: m_CF = 1;
12809: } else {
12810: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
12811: }
12812: }
12813:
1.1 root 12814: inline void msdos_int_21h_7303h()
12815: {
1.1.1.3 root 12816: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
12817: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 12818: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
12819:
12820: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
12821: info->size_of_structure = sizeof(ext_space_info_t);
12822: info->structure_version = 0;
12823: info->sectors_per_cluster = sectors_per_cluster;
12824: info->bytes_per_sector = bytes_per_sector;
12825: info->available_clusters_on_drive = free_clusters;
12826: info->total_clusters_on_drive = total_clusters;
12827: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
12828: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
12829: info->available_allocation_units = free_clusters; // ???
12830: info->total_allocation_units = total_clusters; // ???
12831: } else {
12832: REG16(AX) = errno;
1.1.1.3 root 12833: m_CF = 1;
1.1 root 12834: }
12835: }
12836:
1.1.1.30 root 12837: inline void msdos_int_21h_dbh()
12838: {
12839: // Novell NetWare - Workstation - Get Number of Local Drives
12840: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
12841: REG8(AL) = dos_info->last_drive;
12842: }
12843:
12844: inline void msdos_int_21h_dch()
12845: {
12846: // Novell NetWare - Connection Services - Get Connection Number
12847: REG8(AL) = 0x00;
12848: }
12849:
1.1.1.32 root 12850: inline void msdos_int_24h()
12851: {
12852: const char *message = NULL;
12853: int key = 0;
12854:
12855: for(int i = 0; i < array_length(critical_error_table); i++) {
12856: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
12857: if(active_code_page == 932) {
12858: message = critical_error_table[i].message_japanese;
12859: }
12860: if(message == NULL) {
12861: message = critical_error_table[i].message_english;
12862: }
12863: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
12864: strcpy((char *)(mem + WORK_TOP + 1), message);
12865:
12866: SREG(ES) = WORK_TOP >> 4;
12867: i386_load_segment_descriptor(ES);
12868: REG16(DI) = 0x0000;
12869: break;
12870: }
12871: }
12872: fprintf(stderr, "\n%s", message);
12873: if(!(REG8(AH) & 0x80)) {
12874: if(REG8(AH) & 0x01) {
12875: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
12876: } else {
12877: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
12878: }
12879: }
12880: fprintf(stderr, "\n");
12881:
1.1.1.33 root 12882: {
1.1.1.32 root 12883: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
1.1.1.33 root 12884: }
1.1.1.32 root 12885: if(REG8(AH) & 0x10) {
12886: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
12887: }
12888: if(REG8(AH) & 0x20) {
12889: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
12890: }
12891: if(REG8(AH) & 0x08) {
12892: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
12893: }
12894: fprintf(stderr, "? ");
12895:
12896: while(1) {
12897: while(!_kbhit()) {
12898: Sleep(10);
12899: }
12900: key = _getch();
12901:
12902: if(key == 'I' || key == 'i') {
12903: if(REG8(AH) & 0x20) {
12904: REG8(AL) = 0;
12905: break;
12906: }
12907: } else if(key == 'R' || key == 'r') {
12908: if(REG8(AH) & 0x10) {
12909: REG8(AL) = 1;
12910: break;
12911: }
12912: } else if(key == 'A' || key == 'a') {
12913: REG8(AL) = 2;
12914: break;
12915: } else if(key == 'F' || key == 'f') {
12916: if(REG8(AH) & 0x08) {
12917: REG8(AL) = 3;
12918: break;
12919: }
12920: }
12921: }
12922: fprintf(stderr, "%c\n", key);
12923: }
12924:
1.1 root 12925: inline void msdos_int_25h()
12926: {
12927: UINT16 seg, ofs;
12928: DWORD dwSize;
12929:
1.1.1.3 root 12930: #if defined(HAS_I386)
12931: I386OP(pushf)();
12932: #else
12933: PREFIX86(_pushf());
12934: #endif
1.1 root 12935:
12936: if(!(REG8(AL) < 26)) {
12937: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 12938: m_CF = 1;
1.1 root 12939: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
12940: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12941: m_CF = 1;
1.1 root 12942: } else {
12943: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
12944: char dev[64];
12945: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
12946:
12947: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
12948: if(hFile == INVALID_HANDLE_VALUE) {
12949: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12950: m_CF = 1;
1.1 root 12951: } else {
1.1.1.19 root 12952: UINT32 top_sector = REG16(DX);
12953: UINT16 sector_num = REG16(CX);
12954: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
12955:
12956: if(sector_num == 0xffff) {
12957: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
12958: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
12959: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
12960: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
12961: buffer_addr = (seg << 4) + ofs;
12962: }
12963: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
12964: // REG8(AL) = 0x02; // drive not ready
12965: // m_CF = 1;
12966: // } else
12967: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 12968: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 12969: m_CF = 1;
1.1.1.19 root 12970: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 12971: REG8(AL) = 0x0b; // read error
1.1.1.3 root 12972: m_CF = 1;
1.1 root 12973: }
12974: CloseHandle(hFile);
12975: }
12976: }
12977: }
12978:
12979: inline void msdos_int_26h()
12980: {
1.1.1.42 root 12981: // this operation may cause serious damage for drives, so support only floppy disk...
1.1 root 12982: UINT16 seg, ofs;
12983: DWORD dwSize;
12984:
1.1.1.3 root 12985: #if defined(HAS_I386)
12986: I386OP(pushf)();
12987: #else
12988: PREFIX86(_pushf());
12989: #endif
1.1 root 12990:
12991: if(!(REG8(AL) < 26)) {
12992: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 12993: m_CF = 1;
1.1 root 12994: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
12995: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12996: m_CF = 1;
1.1 root 12997: } else {
12998: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
12999: char dev[64];
13000: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
13001:
13002: if(dpb->media_type == 0xf8) {
13003: // this drive is not a floppy
1.1.1.6 root 13004: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
13005: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
13006: // }
1.1 root 13007: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13008: m_CF = 1;
1.1 root 13009: } else {
13010: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
13011: if(hFile == INVALID_HANDLE_VALUE) {
13012: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13013: m_CF = 1;
1.1 root 13014: } else {
1.1.1.19 root 13015: UINT32 top_sector = REG16(DX);
13016: UINT16 sector_num = REG16(CX);
13017: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
13018:
13019: if(sector_num == 0xffff) {
13020: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
13021: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
13022: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
13023: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
13024: buffer_addr = (seg << 4) + ofs;
13025: }
1.1 root 13026: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
13027: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 13028: m_CF = 1;
1.1.1.19 root 13029: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 13030: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 13031: m_CF = 1;
1.1.1.19 root 13032: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 13033: REG8(AL) = 0x0a; // write error
1.1.1.3 root 13034: m_CF = 1;
1.1 root 13035: }
13036: CloseHandle(hFile);
13037: }
13038: }
13039: }
13040: }
13041:
13042: inline void msdos_int_27h()
13043: {
1.1.1.29 root 13044: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
13045: try {
13046: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
13047: } catch(...) {
13048: // recover the broken mcb
13049: int mcb_seg = SREG(CS) - 1;
13050: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 13051:
1.1.1.29 root 13052: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 13053: mcb->mz = 'M';
13054: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
13055:
1.1.1.29 root 13056: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 13057: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 13058: } else {
1.1.1.39 root 13059: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 13060: }
13061: } else {
13062: mcb->mz = 'Z';
1.1.1.30 root 13063: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 13064: }
13065: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
13066: }
1.1.1.3 root 13067: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 13068: }
13069:
13070: inline void msdos_int_29h()
13071: {
1.1.1.14 root 13072: #if 1
13073: // need to check escape sequences
1.1 root 13074: msdos_putch(REG8(AL));
1.1.1.14 root 13075: #else
13076: DWORD num;
13077: vram_flush();
1.1.1.23 root 13078: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 13079: cursor_moved = true;
13080: #endif
1.1 root 13081: }
13082:
13083: inline void msdos_int_2eh()
13084: {
13085: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
13086: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 13087: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 13088: char *token = my_strtok(tmp, " ");
13089: strcpy(command, token);
13090: strcpy(opt, token + strlen(token) + 1);
13091:
13092: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
13093: param->env_seg = 0;
13094: param->cmd_line.w.l = 44;
13095: param->cmd_line.w.h = (WORK_TOP >> 4);
13096: param->fcb1.w.l = 24;
13097: param->fcb1.w.h = (WORK_TOP >> 4);
13098: param->fcb2.w.l = 24;
13099: param->fcb2.w.h = (WORK_TOP >> 4);
13100:
13101: memset(mem + WORK_TOP + 24, 0x20, 20);
13102:
13103: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
13104: cmd_line->len = strlen(opt);
13105: strcpy(cmd_line->cmd, opt);
13106: cmd_line->cmd[cmd_line->len] = 0x0d;
13107:
1.1.1.28 root 13108: try {
13109: if(msdos_process_exec(command, param, 0)) {
13110: REG16(AX) = 0xffff; // error before processing command
13111: } else {
13112: // set flag to set retval to ax when the started process is terminated
13113: process_t *process = msdos_process_info_get(current_psp);
13114: process->called_by_int2eh = true;
13115: }
13116: } catch(...) {
13117: REG16(AX) = 0xffff; // error before processing command
13118: }
1.1 root 13119: }
13120:
1.1.1.29 root 13121: inline void msdos_int_2fh_05h()
13122: {
13123: switch(REG8(AL)) {
13124: case 0x00:
1.1.1.49! root 13125: // critical error handler is installed
1.1.1.32 root 13126: REG8(AL) = 0xff;
13127: break;
13128: case 0x01:
13129: case 0x02:
13130: for(int i = 0; i < array_length(standard_error_table); i++) {
13131: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
13132: const char *message = NULL;
13133: if(active_code_page == 932) {
13134: message = standard_error_table[i].message_japanese;
13135: }
13136: if(message == NULL) {
13137: message = standard_error_table[i].message_english;
13138: }
13139: strcpy((char *)(mem + WORK_TOP), message);
13140:
13141: SREG(ES) = WORK_TOP >> 4;
13142: i386_load_segment_descriptor(ES);
13143: REG16(DI) = 0x0000;
13144: REG8(AL) = 0x01;
13145: break;
13146: }
13147: }
1.1.1.29 root 13148: break;
13149: default:
13150: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.49! root 13151: REG16(AX) = 0x01;
1.1.1.29 root 13152: m_CF = 1;
13153: }
13154: }
13155:
1.1.1.44 root 13156: inline void msdos_int_2fh_06h()
13157: {
13158: switch(REG8(AL)) {
13159: case 0x00:
13160: // ASSIGN is not installed
1.1.1.49! root 13161: // REG8(AL) = 0x00;
1.1.1.44 root 13162: break;
13163: case 0x01:
13164: // this call is available from within MIRROR.COM even if ASSIGN is not installed
13165: REG16(AX) = 0x01;
13166: m_CF = 1;
13167: break;
13168: default:
13169: 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));
13170: REG16(AX) = 0x01;
13171: m_CF = 1;
13172: break;
13173: }
13174: }
13175:
1.1.1.22 root 13176: inline void msdos_int_2fh_11h()
13177: {
13178: switch(REG8(AL)) {
13179: case 0x00:
1.1.1.29 root 13180: if(i386_read_stack() == 0xdada) {
13181: // MSCDEX is not installed
13182: // REG8(AL) = 0x00;
13183: } else {
13184: // Network Redirector is not installed
13185: // REG8(AL) = 0x00;
13186: }
1.1.1.22 root 13187: break;
13188: default:
1.1.1.43 root 13189: // 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 13190: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 13191: m_CF = 1;
13192: break;
13193: }
13194: }
13195:
1.1.1.21 root 13196: inline void msdos_int_2fh_12h()
13197: {
13198: switch(REG8(AL)) {
1.1.1.22 root 13199: case 0x00:
1.1.1.29 root 13200: // DOS 3.0+ internal functions are installed
1.1.1.22 root 13201: REG8(AL) = 0xff;
13202: break;
1.1.1.29 root 13203: // case 0x01: // DOS 3.0+ internal - Close Current File
13204: case 0x02:
13205: {
13206: UINT16 stack = i386_read_stack();
13207: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
13208: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
13209: i386_load_segment_descriptor(ES);
13210: }
13211: break;
1.1.1.30 root 13212: case 0x03:
13213: SREG(DS) = (DEVICE_TOP >> 4);
13214: i386_load_segment_descriptor(DS);
13215: break;
1.1.1.29 root 13216: case 0x04:
13217: {
13218: UINT16 stack = i386_read_stack();
13219: REG8(AL) = (stack == '/') ? '\\' : stack;
13220: #if defined(HAS_I386)
13221: m_ZF = (REG8(AL) == '\\');
13222: #else
13223: m_ZeroVal = (REG8(AL) != '\\');
13224: #endif
13225: }
13226: break;
13227: case 0x05:
1.1.1.49! root 13228: {
! 13229: UINT16 c = i386_read_stack();
! 13230: if((c >> 0) & 0xff) {
! 13231: msdos_putch((c >> 0) & 0xff);
! 13232: }
! 13233: if((c >> 8) & 0xff) {
! 13234: msdos_putch((c >> 8) & 0xff);
! 13235: }
! 13236: }
1.1.1.29 root 13237: break;
1.1.1.49! root 13238: // case 0x06: // DOS 3.0+ internal - Invoke Critical Error
1.1.1.29 root 13239: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
13240: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
1.1.1.49! root 13241: // case 0x09: // DOS 3.0+ internal - Flush and Free Disk Buffer
1.1.1.29 root 13242: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
13243: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
13244: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
13245: case 0x0d:
13246: {
13247: SYSTEMTIME time;
13248: FILETIME file_time;
13249: WORD dos_date, dos_time;
13250: GetLocalTime(&time);
13251: SystemTimeToFileTime(&time, &file_time);
13252: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
13253: REG16(AX) = dos_date;
13254: REG16(DX) = dos_time;
13255: }
13256: break;
13257: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
13258: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
13259: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
13260: case 0x11:
13261: {
13262: char path[MAX_PATH], *p;
13263: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
13264: my_strupr(path);
13265: while((p = my_strchr(path, '/')) != NULL) {
13266: *p = '\\';
13267: }
13268: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
13269: }
13270: break;
13271: case 0x12:
13272: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
13273: break;
13274: case 0x13:
13275: {
13276: char tmp[2] = {0};
13277: tmp[0] = i386_read_stack();
13278: my_strupr(tmp);
13279: REG8(AL) = tmp[0];
13280: }
13281: break;
13282: case 0x14:
13283: #if defined(HAS_I386)
13284: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
13285: #else
13286: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
13287: #endif
13288: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
13289: break;
13290: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 13291: case 0x16:
13292: if(REG16(BX) < 20) {
13293: SREG(ES) = SFT_TOP >> 4;
13294: i386_load_segment_descriptor(ES);
13295: REG16(DI) = 6 + 0x3b * REG16(BX);
13296:
13297: // update system file table
13298: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
13299: if(file_handler[REG16(BX)].valid) {
13300: int count = 0;
13301: for(int i = 0; i < 20; i++) {
13302: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
13303: count++;
13304: }
13305: }
13306: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
13307: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
13308: _lseek(REG16(BX), 0, SEEK_END);
13309: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
13310: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
13311: } else {
13312: memset(sft, 0, 0x3b);
13313: }
13314: } else {
13315: REG16(AX) = 0x06;
13316: m_CF = 1;
13317: }
13318: break;
1.1.1.49! root 13319: case 0x17:
! 13320: {
! 13321: UINT16 drive = i386_read_stack();
! 13322: if(msdos_is_valid_drive(drive)) {
! 13323: msdos_cds_update(drive);
! 13324: }
! 13325: REG16(SI) = 88 * drive;
! 13326: SREG(DS) = (CDS_TOP >> 4);
! 13327: i386_load_segment_descriptor(DS);
! 13328: }
! 13329: break;
1.1.1.29 root 13330: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
13331: // case 0x19: // DOS 3.0+ internal - Set Drive???
13332: case 0x1a:
13333: {
13334: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
13335: if(path[1] == ':') {
13336: if(path[0] >= 'a' && path[0] <= 'z') {
13337: REG8(AL) = path[0] - 'a' + 1;
13338: } else if(path[0] >= 'A' && path[0] <= 'Z') {
13339: REG8(AL) = path[0] - 'A' + 1;
13340: } else {
13341: REG8(AL) = 0xff; // invalid
13342: }
13343: strcpy(full, path);
13344: strcpy(path, full + 2);
13345: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
13346: if(full[0] >= 'a' && full[0] <= 'z') {
13347: REG8(AL) = full[0] - 'a' + 1;
13348: } else if(full[0] >= 'A' && full[0] <= 'Z') {
13349: REG8(AL) = full[0] - 'A' + 1;
13350: } else {
13351: REG8(AL) = 0xff; // invalid
13352: }
13353: } else {
13354: REG8(AL) = 0x00; // default
13355: }
13356: }
13357: break;
13358: case 0x1b:
13359: {
13360: int year = REG16(CX) + 1980;
13361: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
13362: }
13363: break;
13364: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
13365: // case 0x1d: // DOS 3.0+ internal - Sum Memory
13366: case 0x1e:
13367: {
13368: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
13369: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
13370: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
13371: #if defined(HAS_I386)
13372: m_ZF = (strcmp(full_1st, full_2nd) == 0);
13373: #else
13374: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
13375: #endif
13376: } else {
13377: #if defined(HAS_I386)
13378: m_ZF = (strcmp(path_1st, path_2nd) == 0);
13379: #else
13380: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
13381: #endif
13382: }
13383: }
13384: break;
1.1.1.49! root 13385: case 0x1f:
! 13386: {
! 13387: UINT16 drive = i386_read_stack();
! 13388: if(msdos_is_valid_drive(drive)) {
! 13389: msdos_cds_update(drive);
! 13390: }
! 13391: REG16(SI) = 88 * drive;
! 13392: SREG(ES) = (CDS_TOP >> 4);
! 13393: i386_load_segment_descriptor(ES);
! 13394: }
! 13395: break;
1.1.1.21 root 13396: case 0x20:
13397: {
13398: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
13399:
13400: if(fd < 20) {
13401: SREG(ES) = current_psp;
13402: i386_load_segment_descriptor(ES);
13403: REG16(DI) = offsetof(psp_t, file_table) + fd;
13404: } else {
13405: REG16(AX) = 0x06;
13406: m_CF = 1;
13407: }
13408: }
13409: break;
1.1.1.29 root 13410: case 0x21:
13411: msdos_int_21h_60h(0);
13412: break;
1.1.1.49! root 13413: case 0x22:
! 13414: {
! 13415: sda_t *sda = (sda_t *)(mem + SDA_TOP);
! 13416: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00) != 0xff) {
! 13417: sda->extended_error_code = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00);
! 13418: }
! 13419: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01) != 0xff) {
! 13420: sda->error_class = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01);
! 13421: }
! 13422: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02) != 0xff) {
! 13423: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02);
! 13424: }
! 13425: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03) != 0xff) {
! 13426: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03);
! 13427: }
! 13428: }
! 13429: break;
1.1.1.29 root 13430: // case 0x23: // DOS 3.0+ internal - Check If Character Device
13431: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
13432: case 0x25:
13433: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
13434: break;
13435: case 0x26:
13436: REG8(AL) = REG8(CL);
13437: msdos_int_21h_3dh();
13438: break;
13439: case 0x27:
13440: msdos_int_21h_3eh();
13441: break;
13442: case 0x28:
13443: REG16(AX) = REG16(BP);
13444: msdos_int_21h_42h();
13445: break;
13446: case 0x29:
13447: msdos_int_21h_3fh();
13448: break;
13449: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
13450: case 0x2b:
13451: REG16(AX) = REG16(BP);
13452: msdos_int_21h_44h();
13453: break;
13454: case 0x2c:
13455: REG16(BX) = DEVICE_TOP >> 4;
13456: REG16(AX) = 22;
13457: break;
13458: case 0x2d:
13459: {
13460: sda_t *sda = (sda_t *)(mem + SDA_TOP);
13461: REG16(AX) = sda->extended_error_code;
13462: }
13463: break;
13464: case 0x2e:
13465: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32 root 13466: SREG(ES) = 0x0001;
13467: i386_load_segment_descriptor(ES);
13468: REG16(DI) = 0x00;
13469: } else if(REG8(DL) == 0x08) {
1.1.1.49! root 13470: // dummy parameter error message read routine is at fffc:0010
! 13471: SREG(ES) = DUMMY_TOP >> 4;
1.1.1.22 root 13472: i386_load_segment_descriptor(ES);
1.1.1.32 root 13473: REG16(DI) = 0x0010;
1.1.1.22 root 13474: }
13475: break;
1.1.1.29 root 13476: case 0x2f:
13477: if(REG16(DX) != 0) {
1.1.1.30 root 13478: dos_major_version = REG8(DL);
13479: dos_minor_version = REG8(DH);
1.1.1.29 root 13480: } else {
13481: REG8(DL) = 7;
13482: REG8(DH) = 10;
13483: }
13484: break;
13485: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
13486: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 13487: default:
13488: 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));
13489: REG16(AX) = 0x01;
13490: m_CF = 1;
13491: break;
13492: }
13493: }
13494:
1.1.1.30 root 13495: inline void msdos_int_2fh_13h()
13496: {
13497: static UINT16 prevDS = 0, prevDX = 0;
13498: static UINT16 prevES = 0, prevBX = 0;
13499: UINT16 tmp;
13500:
13501: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
13502: i386_load_segment_descriptor(DS);
13503: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
13504:
13505: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
13506: i386_load_segment_descriptor(ES);
13507: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
13508: }
13509:
1.1.1.22 root 13510: inline void msdos_int_2fh_14h()
13511: {
13512: switch(REG8(AL)) {
13513: case 0x00:
1.1.1.29 root 13514: // NLSFUNC.COM is installed
13515: REG8(AL) = 0xff;
1.1.1.25 root 13516: break;
13517: case 0x01:
13518: case 0x03:
13519: REG8(AL) = 0x00;
13520: active_code_page = REG16(BX);
13521: msdos_nls_tables_update();
13522: break;
13523: case 0x02:
13524: REG8(AL) = get_extended_country_info(REG16(BP));
13525: break;
13526: case 0x04:
1.1.1.42 root 13527: for(int i = 0;; i++) {
13528: if(country_table[i].code == REG16(DX)) {
13529: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
13530: break;
13531: } else if(country_table[i].code == -1) {
13532: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
13533: break;
13534: }
13535: }
1.1.1.25 root 13536: REG8(AL) = 0x00;
1.1.1.22 root 13537: break;
13538: default:
13539: 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));
13540: REG16(AX) = 0x01;
13541: m_CF = 1;
13542: break;
13543: }
13544: }
13545:
13546: inline void msdos_int_2fh_15h()
13547: {
13548: switch(REG8(AL)) {
1.1.1.29 root 13549: case 0x00: // CD-ROM - Installation Check
13550: if(REG16(BX) == 0x0000) {
1.1.1.43 root 13551: #if 0
13552: // MSCDEX is installed
13553: REG16(BX) = 0;
13554: for(int i = 0, n = 0; i < 26; i++) {
1.1.1.44 root 13555: if(msdos_is_cdrom_drive(i)) {
13556: if(REG16(BX) == 0) {
13557: REG16(CX) = i;
1.1.1.43 root 13558: }
1.1.1.44 root 13559: REG16(BX)++;
1.1.1.43 root 13560: }
13561: }
13562: #else
1.1.1.29 root 13563: // MSCDEX is not installed
13564: // REG8(AL) = 0x00;
1.1.1.43 root 13565: #endif
1.1.1.29 root 13566: } else {
13567: // GRAPHICS.COM is not installed
13568: // REG8(AL) = 0x00;
13569: }
1.1.1.22 root 13570: break;
1.1.1.43 root 13571: case 0x0b:
1.1.1.44 root 13572: // this call is available from within DOSSHELL even if MSCDEX is not installed
13573: REG16(AX) = msdos_is_cdrom_drive(REG8(CL)) ? 0x5ad8 : 0x0000;
13574: REG16(BX) = 0xadad;
1.1.1.43 root 13575: break;
13576: case 0x0d:
1.1.1.44 root 13577: for(int i = 0, n = 0; i < 26; i++) {
13578: if(msdos_is_cdrom_drive(i)) {
13579: mem[SREG_BASE(ES) + REG16(BX) + (n++)] = i;
1.1.1.43 root 13580: }
13581: }
13582: break;
1.1.1.22 root 13583: case 0xff:
1.1.1.29 root 13584: if(REG16(BX) == 0x0000) {
13585: // CORELCDX is not installed
13586: } else {
13587: 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));
13588: REG16(AX) = 0x01;
13589: m_CF = 1;
13590: }
1.1.1.22 root 13591: break;
1.1.1.21 root 13592: default:
1.1.1.22 root 13593: 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 13594: REG16(AX) = 0x01;
13595: m_CF = 1;
13596: break;
13597: }
13598: }
13599:
1.1 root 13600: inline void msdos_int_2fh_16h()
13601: {
13602: switch(REG8(AL)) {
13603: case 0x00:
1.1.1.14 root 13604: if(no_windows) {
1.1.1.29 root 13605: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
13606: // REG8(AL) = 0x00;
1.1.1.14 root 13607: } else {
1.1.1.30 root 13608: REG8(AL) = win_major_version;
13609: REG8(AH) = win_minor_version;
1.1 root 13610: }
13611: break;
1.1.1.43 root 13612: case 0x05: // Windows Enhanced Mode & 286 DOSX Init Broadcast
1.1.1.30 root 13613: // from DOSBox
13614: i386_set_a20_line(1);
13615: break;
1.1.1.49! root 13616: case 0x06: // Windows Enhanced Mode & 286 DOSX Exit Broadcast
1.1.1.43 root 13617: case 0x08: // Windows Enhanced Mode Init Complete Broadcast
13618: case 0x09: // Windows Enhanced Mode Begin Exit Broadcast
13619: break;
13620: case 0x07:
13621: // Virtual Device Call API
13622: break;
1.1.1.22 root 13623: case 0x0a:
13624: if(!no_windows) {
13625: REG16(AX) = 0x0000;
1.1.1.30 root 13626: REG8(BH) = win_major_version;
13627: REG8(BL) = win_minor_version;
1.1.1.49! root 13628: // REG16(CX) = 0x0002; // standard
1.1.1.22 root 13629: REG16(CX) = 0x0003; // enhanced
13630: }
13631: break;
1.1.1.30 root 13632: case 0x0b:
13633: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 13634: case 0x0e:
13635: case 0x0f:
1.1.1.30 root 13636: case 0x10:
1.1.1.22 root 13637: case 0x11:
13638: case 0x12:
13639: case 0x13:
13640: case 0x14:
1.1.1.30 root 13641: case 0x15:
1.1.1.43 root 13642: case 0x81:
13643: case 0x82:
1.1.1.44 root 13644: case 0x84:
1.1.1.49! root 13645: case 0x85:
1.1.1.33 root 13646: case 0x86:
1.1.1.22 root 13647: case 0x87:
1.1.1.30 root 13648: case 0x89:
1.1.1.33 root 13649: case 0x8a:
1.1.1.22 root 13650: // function not supported, do not clear AX
13651: break;
1.1.1.14 root 13652: case 0x80:
13653: Sleep(10);
1.1.1.35 root 13654: REQUEST_HARDWRE_UPDATE();
1.1.1.29 root 13655: REG8(AL) = 0x00;
1.1.1.14 root 13656: break;
1.1.1.33 root 13657: case 0x83:
13658: REG16(BX) = 0x01; // system vm id
13659: break;
1.1.1.22 root 13660: case 0x8e:
13661: REG16(AX) = 0x00; // failed
13662: break;
1.1.1.20 root 13663: case 0x8f:
13664: switch(REG8(DH)) {
13665: case 0x01:
1.1.1.49! root 13666: // REG16(AX) = 0x0000; // close command selected but not yet acknowledged
! 13667: // REG16(AX) = 0x0001; // close command issued and acknowledged
! 13668: REG16(AX) = 0x168f; // close command not selected -- application should continue
! 13669: break;
! 13670: default:
! 13671: REG16(AX) = 0x0000; // successful
1.1.1.20 root 13672: break;
13673: }
13674: break;
1.1 root 13675: default:
1.1.1.22 root 13676: 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));
13677: REG16(AX) = 0x01;
13678: m_CF = 1;
13679: break;
13680: }
13681: }
13682:
13683: inline void msdos_int_2fh_19h()
13684: {
13685: switch(REG8(AL)) {
13686: case 0x00:
1.1.1.29 root 13687: // SHELLB.COM is not installed
13688: // REG8(AL) = 0x00;
1.1.1.22 root 13689: break;
13690: case 0x01:
13691: case 0x02:
13692: case 0x03:
13693: case 0x04:
13694: REG16(AX) = 0x01;
13695: m_CF = 1;
13696: break;
1.1.1.29 root 13697: case 0x80:
13698: // IBM ROM-DOS v4.0 is not installed
13699: // REG8(AL) = 0x00;
13700: break;
1.1.1.22 root 13701: default:
13702: 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 13703: REG16(AX) = 0x01;
1.1.1.3 root 13704: m_CF = 1;
1.1 root 13705: break;
13706: }
13707: }
13708:
13709: inline void msdos_int_2fh_1ah()
13710: {
13711: switch(REG8(AL)) {
13712: case 0x00:
1.1.1.29 root 13713: // ANSI.SYS is installed
1.1 root 13714: REG8(AL) = 0xff;
13715: break;
1.1.1.49! root 13716: case 0x01:
! 13717: if(REG8(CL) == 0x7f) {
! 13718: // get display information
! 13719: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
! 13720: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
! 13721: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
! 13722: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
! 13723: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
! 13724: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
! 13725: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
! 13726: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
! 13727: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
! 13728: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
! 13729: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
! 13730: // } else if(REG8(CL) == 0x5f) {
! 13731: // // set display information
! 13732: } else {
! 13733: 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));
! 13734: REG16(AX) = 0x01;
! 13735: m_CF = 1;
! 13736: }
! 13737: break;
1.1 root 13738: default:
1.1.1.22 root 13739: 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));
13740: REG16(AX) = 0x01;
13741: m_CF = 1;
13742: break;
13743: }
13744: }
13745:
1.1.1.30 root 13746: inline void msdos_int_2fh_40h()
1.1.1.22 root 13747: {
13748: switch(REG8(AL)) {
13749: case 0x00:
1.1.1.30 root 13750: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
13751: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 13752: break;
1.1.1.43 root 13753: case 0x10:
13754: // OS/2 v2.0+ - Installation Check
13755: REG16(AX) = 0x01;
13756: m_CF = 1;
13757: break;
1.1.1.22 root 13758: default:
13759: 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 13760: REG16(AX) = 0x01;
1.1.1.3 root 13761: m_CF = 1;
1.1 root 13762: break;
13763: }
13764: }
13765:
13766: inline void msdos_int_2fh_43h()
13767: {
13768: switch(REG8(AL)) {
13769: case 0x00:
1.1.1.29 root 13770: // XMS is installed ?
1.1.1.19 root 13771: #ifdef SUPPORT_XMS
13772: if(support_xms) {
13773: REG8(AL) = 0x80;
1.1.1.44 root 13774: }
13775: #endif
13776: break;
13777: case 0x08:
13778: #ifdef SUPPORT_XMS
13779: if(support_xms) {
13780: REG8(AL) = 0x43;
13781: REG8(BL) = 0x01; // IBM PC/AT
13782: REG8(BH) = 0x01; // Fast AT A20 switch time
13783: }
1.1.1.19 root 13784: #endif
13785: break;
13786: case 0x10:
13787: SREG(ES) = XMS_TOP >> 4;
13788: i386_load_segment_descriptor(ES);
1.1.1.26 root 13789: REG16(BX) = 0x15;
1.1 root 13790: break;
1.1.1.44 root 13791: case 0xe0:
13792: // DOS Protected Mode Services (DPMS) v1.0 is not installed
13793: if(REG16(BX) == 0x0000 && REG16(CX) == 0x4450 && REG16(DX) == 0x4d53) {
13794: break;
13795: }
1.1 root 13796: default:
1.1.1.22 root 13797: 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));
13798: REG16(AX) = 0x01;
13799: m_CF = 1;
13800: break;
13801: }
13802: }
13803:
13804: inline void msdos_int_2fh_46h()
13805: {
13806: switch(REG8(AL)) {
13807: case 0x80:
1.1.1.29 root 13808: // Windows v3.0 is not installed
13809: // REG8(AL) = 0x00;
1.1.1.22 root 13810: break;
13811: default:
13812: 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));
13813: REG16(AX) = 0x01;
13814: m_CF = 1;
13815: break;
13816: }
13817: }
13818:
13819: inline void msdos_int_2fh_48h()
13820: {
13821: switch(REG8(AL)) {
13822: case 0x00:
1.1.1.29 root 13823: // DOSKEY is not installed
13824: // REG8(AL) = 0x00;
1.1.1.22 root 13825: break;
13826: case 0x10:
13827: msdos_int_21h_0ah();
13828: REG16(AX) = 0x00;
13829: break;
13830: default:
13831: 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 13832: REG16(AX) = 0x01;
1.1.1.3 root 13833: m_CF = 1;
1.1 root 13834: break;
13835: }
13836: }
13837:
13838: inline void msdos_int_2fh_4ah()
13839: {
13840: switch(REG8(AL)) {
1.1.1.29 root 13841: #ifdef SUPPORT_HMA
13842: case 0x01: // DOS 5.0+ - Query Free HMA Space
13843: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
13844: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13845: // restore first free mcb in high memory area
13846: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13847: }
13848: int offset = 0xffff;
13849: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
13850: REG16(DI) = offset + 0x10;
13851: } else {
13852: REG16(DI) = 0xffff;
13853: }
13854: } else {
13855: // HMA is already used
13856: REG16(BX) = 0;
13857: REG16(DI) = 0xffff;
13858: }
13859: SREG(ES) = 0xffff;
13860: i386_load_segment_descriptor(ES);
13861: break;
13862: case 0x02: // DOS 5.0+ - Allocate HMA Space
13863: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
13864: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13865: // restore first free mcb in high memory area
13866: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13867: }
13868: int size = REG16(BX), offset;
13869: if((size % 16) != 0) {
13870: size &= ~15;
13871: size += 16;
13872: }
13873: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
13874: REG16(BX) = size;
13875: REG16(DI) = offset + 0x10;
13876: is_hma_used_by_int_2fh = true;
13877: } else {
13878: REG16(BX) = 0;
13879: REG16(DI) = 0xffff;
13880: }
13881: } else {
13882: // HMA is already used
13883: REG16(BX) = 0;
13884: REG16(DI) = 0xffff;
13885: }
13886: SREG(ES) = 0xffff;
13887: i386_load_segment_descriptor(ES);
13888: break;
13889: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
13890: if(REG8(DL) == 0x00) {
13891: if(!is_hma_used_by_xms) {
13892: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13893: // restore first free mcb in high memory area
13894: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13895: is_hma_used_by_int_2fh = false;
13896: }
13897: int size = REG16(BX), offset;
13898: if((size % 16) != 0) {
13899: size &= ~15;
13900: size += 16;
13901: }
13902: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
13903: // REG16(BX) = size;
13904: SREG(ES) = 0xffff;
13905: i386_load_segment_descriptor(ES);
13906: REG16(DI) = offset + 0x10;
13907: is_hma_used_by_int_2fh = true;
13908: } else {
13909: REG16(DI) = 0xffff;
13910: }
13911: } else {
13912: REG16(DI) = 0xffff;
13913: }
13914: } else if(REG8(DL) == 0x01) {
13915: if(!is_hma_used_by_xms) {
13916: int size = REG16(BX);
13917: if((size % 16) != 0) {
13918: size &= ~15;
13919: size += 16;
13920: }
13921: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
13922: // memory block address is not changed
13923: } else {
13924: REG16(DI) = 0xffff;
13925: }
13926: } else {
13927: REG16(DI) = 0xffff;
13928: }
13929: } else if(REG8(DL) == 0x02) {
13930: if(!is_hma_used_by_xms) {
13931: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13932: // restore first free mcb in high memory area
13933: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13934: is_hma_used_by_int_2fh = false;
13935: } else {
13936: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
13937: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
13938: is_hma_used_by_int_2fh = false;
13939: }
13940: }
13941: }
13942: } else {
13943: 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));
13944: REG16(AX) = 0x01;
13945: m_CF = 1;
13946: }
13947: break;
13948: case 0x04: // Windows95 - Get Start of HMA Memory Chain
13949: if(!is_hma_used_by_xms) {
13950: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13951: // restore first free mcb in high memory area
13952: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13953: is_hma_used_by_int_2fh = false;
13954: }
13955: REG16(AX) = 0x0000;
13956: SREG(ES) = 0xffff;
13957: i386_load_segment_descriptor(ES);
13958: REG16(DI) = 0x10;
13959: }
13960: break;
13961: #else
1.1 root 13962: case 0x01:
13963: case 0x02:
1.1.1.29 root 13964: // HMA is already used
1.1.1.27 root 13965: REG16(BX) = 0x0000;
1.1.1.3 root 13966: SREG(ES) = 0xffff;
13967: i386_load_segment_descriptor(ES);
1.1 root 13968: REG16(DI) = 0xffff;
13969: break;
1.1.1.19 root 13970: case 0x03:
13971: // unable to allocate
13972: REG16(DI) = 0xffff;
13973: break;
13974: case 0x04:
13975: // function not supported, do not clear AX
13976: break;
1.1.1.29 root 13977: #endif
13978: case 0x10:
1.1.1.42 root 13979: switch(REG16(BX)) {
13980: case 0x0000:
13981: case 0x0001:
13982: case 0x0002:
13983: case 0x0003:
13984: case 0x0004:
13985: case 0x0005:
13986: case 0x0006:
13987: case 0x0007:
13988: case 0x0008:
13989: case 0x000a:
13990: case 0x1234:
13991: // SMARTDRV v4.00+ is not installed
13992: break;
13993: default:
1.1.1.29 root 13994: 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));
13995: REG16(AX) = 0x01;
13996: m_CF = 1;
1.1.1.42 root 13997: break;
1.1.1.29 root 13998: }
13999: break;
14000: case 0x11:
1.1.1.42 root 14001: switch(REG16(BX)) {
14002: case 0x0000:
14003: case 0x0001:
14004: case 0x0002:
14005: case 0x0003:
14006: case 0x0004:
14007: case 0x0005:
14008: case 0x0006:
14009: case 0x0007:
14010: case 0x0008:
14011: case 0x0009:
14012: case 0x000a:
14013: case 0x000b:
14014: case 0xfffe:
14015: case 0xffff:
1.1.1.29 root 14016: // DBLSPACE.BIN is not installed
1.1.1.42 root 14017: break;
14018: default:
14019: 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));
14020: REG16(AX) = 0x01;
14021: m_CF = 1;
14022: break;
14023: }
14024: break;
14025: case 0x12:
14026: if(REG16(CX) == 0x4d52 && REG16(DX) == 0x4349) {
14027: // Microsoft Realtime Compression Interface (MRCI) is not installed
14028: } else if(REG16(CX) == 0x5354 && REG16(DX) == 0x4143) {
14029: // Stacker 4 LZS Compression Interface (LZSAPI) is not installed
1.1.1.29 root 14030: } else {
14031: 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));
14032: REG16(AX) = 0x01;
14033: m_CF = 1;
14034: }
1.1.1.22 root 14035: break;
1.1.1.42 root 14036: case 0x13:
14037: // DBLSPACE.BIN is not installed
14038: break;
1.1.1.22 root 14039: default:
14040: 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));
14041: REG16(AX) = 0x01;
14042: m_CF = 1;
14043: break;
14044: }
14045: }
14046:
14047: inline void msdos_int_2fh_4bh()
14048: {
14049: switch(REG8(AL)) {
1.1.1.24 root 14050: case 0x01:
1.1.1.22 root 14051: case 0x02:
1.1.1.29 root 14052: // Task Switcher is not installed
1.1.1.24 root 14053: break;
14054: case 0x03:
14055: // this call is available from within DOSSHELL even if the task switcher is not installed
14056: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 14057: break;
1.1.1.30 root 14058: case 0x04:
14059: REG16(BX) = 0x0000; // free switcher id successfully
14060: break;
1.1.1.43 root 14061: case 0x05:
14062: REG16(BX) = 0x0000; // no instance data chain
14063: SREG(ES) = 0x0000;
14064: i386_load_segment_descriptor(ES);
14065: break;
1.1 root 14066: default:
1.1.1.22 root 14067: 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 14068: REG16(AX) = 0x01;
1.1.1.3 root 14069: m_CF = 1;
1.1 root 14070: break;
14071: }
14072: }
14073:
1.1.1.44 root 14074: inline void msdos_int_2fh_4dh()
14075: {
14076: switch(REG8(AL)) {
14077: case 0x00:
14078: // KKCFUNC is not installed ???
14079: break;
14080: default:
14081: // 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));
14082: REG16(AX) = 0x01; // invalid function
14083: m_CF = 1;
14084: break;
14085: }
14086: }
14087:
1.1 root 14088: inline void msdos_int_2fh_4fh()
14089: {
14090: switch(REG8(AL)) {
14091: case 0x00:
1.1.1.29 root 14092: // BILING is installed
1.1.1.27 root 14093: REG16(AX) = 0x0000;
14094: REG8(DL) = 0x01; // major version
14095: REG8(DH) = 0x00; // minor version
1.1 root 14096: break;
14097: case 0x01:
1.1.1.27 root 14098: REG16(AX) = 0x0000;
1.1 root 14099: REG16(BX) = active_code_page;
14100: break;
14101: default:
1.1.1.22 root 14102: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
14103: REG16(AX) = 0x01;
14104: m_CF = 1;
14105: break;
14106: }
14107: }
14108:
14109: inline void msdos_int_2fh_55h()
14110: {
14111: switch(REG8(AL)) {
14112: case 0x00:
14113: case 0x01:
14114: // 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));
14115: break;
14116: default:
14117: 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 14118: REG16(AX) = 0x01;
1.1.1.3 root 14119: m_CF = 1;
1.1 root 14120: break;
14121: }
14122: }
14123:
1.1.1.44 root 14124: inline void msdos_int_2fh_56h()
14125: {
14126: switch(REG8(AL)) {
14127: case 0x00:
14128: // INTERLNK is not installed
14129: break;
14130: case 0x01:
14131: // this call is available from within SCANDISK even if INTERLNK is not installed
14132: // if(msdos_is_remote_drive(REG8(BH))) {
14133: // REG8(AL) = 0x00;
14134: // }
14135: break;
14136: default:
14137: 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));
14138: REG16(AX) = 0x01;
14139: m_CF = 1;
14140: break;
14141: }
14142: }
14143:
1.1.1.24 root 14144: inline void msdos_int_2fh_adh()
14145: {
14146: switch(REG8(AL)) {
14147: case 0x00:
1.1.1.29 root 14148: // DISPLAY.SYS is installed
1.1.1.24 root 14149: REG8(AL) = 0xff;
14150: REG16(BX) = 0x100; // ???
14151: break;
14152: case 0x01:
14153: active_code_page = REG16(BX);
14154: msdos_nls_tables_update();
14155: REG16(AX) = 0x01;
14156: break;
14157: case 0x02:
14158: REG16(BX) = active_code_page;
14159: break;
14160: case 0x03:
14161: // FIXME
14162: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
14163: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
14164: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
14165: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
14166: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
14167: break;
14168: case 0x80:
1.1.1.49! root 14169: // KEYB.COM is not installed
! 14170: break;
1.1.1.24 root 14171: default:
14172: 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));
14173: REG16(AX) = 0x01;
14174: m_CF = 1;
14175: break;
14176: }
14177: }
14178:
1.1 root 14179: inline void msdos_int_2fh_aeh()
14180: {
14181: switch(REG8(AL)) {
14182: case 0x00:
1.1.1.28 root 14183: // FIXME: we need to check the given command line
14184: REG8(AL) = 0x00; // the command should be executed as usual
14185: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 14186: break;
14187: case 0x01:
14188: {
14189: char command[MAX_PATH];
14190: memset(command, 0, sizeof(command));
1.1.1.3 root 14191: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 14192:
14193: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
14194: param->env_seg = 0;
14195: param->cmd_line.w.l = 44;
14196: param->cmd_line.w.h = (WORK_TOP >> 4);
14197: param->fcb1.w.l = 24;
14198: param->fcb1.w.h = (WORK_TOP >> 4);
14199: param->fcb2.w.l = 24;
14200: param->fcb2.w.h = (WORK_TOP >> 4);
14201:
14202: memset(mem + WORK_TOP + 24, 0x20, 20);
14203:
14204: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 14205: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
14206: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 14207: cmd_line->cmd[cmd_line->len] = 0x0d;
14208:
1.1.1.28 root 14209: try {
14210: msdos_process_exec(command, param, 0);
14211: } catch(...) {
14212: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 14213: }
14214: }
14215: break;
14216: default:
1.1.1.22 root 14217: 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 14218: REG16(AX) = 0x01;
1.1.1.3 root 14219: m_CF = 1;
1.1 root 14220: break;
14221: }
14222: }
14223:
1.1.1.34 root 14224: inline void msdos_int_2fh_b7h()
14225: {
14226: switch(REG8(AL)) {
14227: case 0x00:
14228: // APPEND is not installed
14229: // REG8(AL) = 0x00;
14230: break;
1.1.1.44 root 14231: case 0x06:
14232: REG16(BX) = 0x0000;
14233: break;
1.1.1.34 root 14234: case 0x07:
1.1.1.43 root 14235: case 0x11:
1.1.1.34 root 14236: // COMMAND.COM calls this service without checking APPEND is installed
14237: break;
14238: default:
14239: 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));
14240: REG16(AX) = 0x01;
14241: m_CF = 1;
14242: break;
14243: }
14244: }
14245:
1.1.1.24 root 14246: inline void msdos_int_33h_0000h()
14247: {
14248: REG16(AX) = 0xffff; // hardware/driver installed
14249: REG16(BX) = MAX_MOUSE_BUTTONS;
14250: }
14251:
14252: inline void msdos_int_33h_0001h()
14253: {
1.1.1.34 root 14254: if(mouse.hidden > 0) {
14255: mouse.hidden--;
14256: }
14257: if(mouse.hidden == 0) {
1.1.1.24 root 14258: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
14259: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
14260: }
14261: pic[1].imr &= ~0x10; // enable irq12
14262: }
14263: }
14264:
14265: inline void msdos_int_33h_0002h()
14266: {
1.1.1.34 root 14267: mouse.hidden++;
14268: // SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode & ~ENABLE_MOUSE_INPUT);
14269: pic[1].imr |= 0x10; // enable irq12
1.1.1.24 root 14270: }
14271:
14272: inline void msdos_int_33h_0003h()
14273: {
1.1.1.34 root 14274: // if(mouse.hidden > 0) {
14275: update_console_input();
14276: // }
1.1.1.24 root 14277: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 14278: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
14279: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
14280: }
14281:
14282: inline void msdos_int_33h_0004h()
14283: {
14284: mouse.position.x = REG16(CX);
14285: mouse.position.x = REG16(DX);
1.1.1.24 root 14286: }
14287:
14288: inline void msdos_int_33h_0005h()
14289: {
1.1.1.34 root 14290: // if(mouse.hidden > 0) {
14291: update_console_input();
14292: // }
1.1.1.24 root 14293: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
14294: int idx = REG16(BX);
1.1.1.34 root 14295: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff);
14296: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x));
14297: 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 14298: mouse.buttons[idx].pressed_times = 0;
14299: } else {
14300: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
14301: }
14302: REG16(AX) = mouse.get_buttons();
14303: }
14304:
14305: inline void msdos_int_33h_0006h()
14306: {
1.1.1.34 root 14307: // if(mouse.hidden > 0) {
14308: update_console_input();
14309: // }
1.1.1.24 root 14310: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
14311: int idx = REG16(BX);
1.1.1.34 root 14312: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff);
14313: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x));
14314: 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 14315: mouse.buttons[idx].released_times = 0;
14316: } else {
14317: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
14318: }
14319: REG16(AX) = mouse.get_buttons();
14320: }
14321:
14322: inline void msdos_int_33h_0007h()
14323: {
14324: mouse.min_position.x = min(REG16(CX), REG16(DX));
14325: mouse.max_position.x = max(REG16(CX), REG16(DX));
14326: }
14327:
14328: inline void msdos_int_33h_0008h()
14329: {
14330: mouse.min_position.y = min(REG16(CX), REG16(DX));
14331: mouse.max_position.y = max(REG16(CX), REG16(DX));
14332: }
14333:
14334: inline void msdos_int_33h_0009h()
14335: {
14336: mouse.hot_spot[0] = REG16(BX);
14337: mouse.hot_spot[1] = REG16(CX);
14338: }
14339:
1.1.1.49! root 14340: inline void msdos_int_33h_000ah()
! 14341: {
! 14342: mouse.screen_mask = REG16(CX);
! 14343: mouse.cursor_mask = REG16(DX);
! 14344: }
! 14345:
1.1.1.24 root 14346: inline void msdos_int_33h_000bh()
14347: {
1.1.1.34 root 14348: // if(mouse.hidden > 0) {
14349: update_console_input();
14350: // }
1.1.1.24 root 14351: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
14352: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
14353: mouse.prev_position.x = mouse.position.x;
14354: mouse.prev_position.y = mouse.position.y;
14355: REG16(CX) = dx;
14356: REG16(DX) = dy;
14357: }
14358:
14359: inline void msdos_int_33h_000ch()
14360: {
14361: mouse.call_mask = REG16(CX);
14362: mouse.call_addr.w.l = REG16(DX);
14363: mouse.call_addr.w.h = SREG(ES);
14364: }
14365:
14366: inline void msdos_int_33h_000fh()
14367: {
14368: mouse.mickey.x = REG16(CX);
14369: mouse.mickey.y = REG16(DX);
14370: }
14371:
14372: inline void msdos_int_33h_0011h()
14373: {
14374: REG16(AX) = 0xffff;
14375: REG16(BX) = MAX_MOUSE_BUTTONS;
14376: }
14377:
14378: inline void msdos_int_33h_0014h()
14379: {
14380: UINT16 old_mask = mouse.call_mask;
14381: UINT16 old_ofs = mouse.call_addr.w.l;
14382: UINT16 old_seg = mouse.call_addr.w.h;
14383:
14384: mouse.call_mask = REG16(CX);
14385: mouse.call_addr.w.l = REG16(DX);
14386: mouse.call_addr.w.h = SREG(ES);
14387:
14388: REG16(CX) = old_mask;
14389: REG16(DX) = old_ofs;
14390: SREG(ES) = old_seg;
14391: i386_load_segment_descriptor(ES);
14392: }
14393:
14394: inline void msdos_int_33h_0015h()
14395: {
14396: REG16(BX) = sizeof(mouse);
14397: }
14398:
14399: inline void msdos_int_33h_0016h()
14400: {
14401: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
14402: }
14403:
14404: inline void msdos_int_33h_0017h()
14405: {
14406: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
14407: }
14408:
1.1.1.43 root 14409: inline void msdos_int_33h_0018h()
14410: {
14411: for(int i = 0; i < 8; i++) {
14412: if(REG16(CX) & (1 << i)) {
14413: if(mouse.call_addr_alt[i].dw && !(REG16(DX) == 0 && SREG(ES) == 0)) {
14414: // event handler already exists
14415: REG16(AX) = 0xffff;
14416: break;
14417: }
14418: mouse.call_addr_alt[i].w.l = REG16(DX);
14419: mouse.call_addr_alt[i].w.h = SREG(ES);
14420: }
14421: }
14422: }
14423:
14424: inline void msdos_int_33h_0019h()
14425: {
14426: UINT16 call_mask = REG16(CX);
14427:
14428: REG16(CX) = 0;
14429:
14430: for(int i = 0; i < 8; i++) {
14431: if((call_mask & (1 << i)) && mouse.call_addr_alt[i].dw) {
14432: for(int j = 0; j < 8; j++) {
14433: if((call_mask & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
14434: REG16(CX) |= (1 << j);
14435: }
14436: }
14437: REG16(DX) = mouse.call_addr_alt[i].w.l;
14438: REG16(BX) = mouse.call_addr_alt[i].w.h;
14439: break;
14440: }
14441: }
14442: }
14443:
1.1.1.24 root 14444: inline void msdos_int_33h_001ah()
14445: {
14446: mouse.sensitivity[0] = REG16(BX);
14447: mouse.sensitivity[1] = REG16(CX);
14448: mouse.sensitivity[2] = REG16(DX);
14449: }
14450:
14451: inline void msdos_int_33h_001bh()
14452: {
14453: REG16(BX) = mouse.sensitivity[0];
14454: REG16(CX) = mouse.sensitivity[1];
14455: REG16(DX) = mouse.sensitivity[2];
14456: }
14457:
14458: inline void msdos_int_33h_001dh()
14459: {
14460: mouse.display_page = REG16(BX);
14461: }
14462:
14463: inline void msdos_int_33h_001eh()
14464: {
14465: REG16(BX) = mouse.display_page;
14466: }
14467:
1.1.1.34 root 14468: inline void msdos_int_33h_001fh()
14469: {
14470: // from DOSBox
14471: REG16(BX) = 0x0000;
14472: SREG(ES) = 0x0000;
14473: i386_load_segment_descriptor(ES);
14474: mouse.enabled = false;
14475: mouse.old_hidden = mouse.hidden;
14476: mouse.hidden = 1;
14477: }
14478:
14479: inline void msdos_int_33h_0020h()
14480: {
14481: // from DOSBox
14482: mouse.enabled = true;
14483: mouse.hidden = mouse.old_hidden;
14484: }
14485:
1.1.1.24 root 14486: inline void msdos_int_33h_0021h()
14487: {
14488: REG16(AX) = 0xffff;
14489: REG16(BX) = MAX_MOUSE_BUTTONS;
14490: }
14491:
14492: inline void msdos_int_33h_0022h()
14493: {
14494: mouse.language = REG16(BX);
14495: }
14496:
14497: inline void msdos_int_33h_0023h()
14498: {
14499: REG16(BX) = mouse.language;
14500: }
14501:
14502: inline void msdos_int_33h_0024h()
14503: {
14504: REG16(BX) = 0x0805; // V8.05
14505: REG16(CX) = 0x0400; // PS/2
14506: }
14507:
1.1.1.49! root 14508: inline void msdos_int_33h_0025h()
! 14509: {
! 14510: REG16(AX) = 0x8000; // driver (not TSR), software text cursor
! 14511: }
! 14512:
1.1.1.24 root 14513: inline void msdos_int_33h_0026h()
14514: {
14515: REG16(BX) = 0x0000;
14516: REG16(CX) = mouse.max_position.x;
14517: REG16(DX) = mouse.max_position.y;
14518: }
14519:
1.1.1.49! root 14520: inline void msdos_int_33h_0027h()
! 14521: {
! 14522: // if(mouse.hidden > 0) {
! 14523: update_console_input();
! 14524: // }
! 14525: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
! 14526: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
! 14527: mouse.prev_position.x = mouse.position.x;
! 14528: mouse.prev_position.y = mouse.position.y;
! 14529: REG16(AX) = mouse.screen_mask;
! 14530: REG16(BX) = mouse.cursor_mask;
! 14531: REG16(CX) = dx;
! 14532: REG16(DX) = dy;
! 14533: }
! 14534:
! 14535: inline void msdos_int_33h_0028h()
! 14536: {
! 14537: if(REG16(CX) != 0) {
! 14538: UINT8 tmp = REG8(AL);
! 14539: REG8(AL) = REG8(CL);
! 14540: pcbios_int_10h_00h();
! 14541: REG8(AL) = tmp;
! 14542: }
! 14543: REG8(CL) = 0x00; // successful
! 14544: }
! 14545:
! 14546: inline void msdos_int_33h_0029h()
! 14547: {
! 14548: switch(REG16(CX)) {
! 14549: case 0x0000:
! 14550: REG16(CX) = 0x0003;
! 14551: sprintf((char *)(mem + WORK_TOP), "TEXT Mode (80x25)$");
! 14552: break;
! 14553: case 0x0003:
! 14554: REG16(CX) = 0x0070;
! 14555: sprintf((char *)(mem + WORK_TOP), "V-TEXT Mode (%dx%d)$", scr_width, scr_height);
! 14556: break;
! 14557: case 0x0070:
! 14558: REG16(CX) = 0x0071;
! 14559: sprintf((char *)(mem + WORK_TOP), "Extended CGA V-TEXT Mode (%dx%d)$", scr_width, scr_height);
! 14560: break;
! 14561: case 0x0071:
! 14562: REG16(CX) = 0x0073;
! 14563: sprintf((char *)(mem + WORK_TOP), "Extended CGA TEXT Mode (80x25)$");
! 14564: break;
! 14565: default:
! 14566: REG16(CX) = 0x0000;
! 14567: break;
! 14568: }
! 14569: if(REG16(CX) != 0) {
! 14570: SREG(DS) = (WORK_TOP >> 4);
! 14571: } else {
! 14572: SREG(DS) = 0x0000;
! 14573: }
! 14574: i386_load_segment_descriptor(DS);
! 14575: REG16(DX) = 0x0000;
! 14576: }
! 14577:
1.1.1.24 root 14578: inline void msdos_int_33h_002ah()
14579: {
1.1.1.34 root 14580: REG16(AX) = -mouse.hidden;
1.1.1.24 root 14581: REG16(BX) = mouse.hot_spot[0];
14582: REG16(CX) = mouse.hot_spot[1];
14583: REG16(DX) = 4; // PS/2
14584: }
14585:
14586: inline void msdos_int_33h_0031h()
14587: {
14588: REG16(AX) = mouse.min_position.x;
14589: REG16(BX) = mouse.min_position.y;
14590: REG16(CX) = mouse.max_position.x;
14591: REG16(DX) = mouse.max_position.y;
14592: }
14593:
14594: inline void msdos_int_33h_0032h()
14595: {
14596: REG16(AX) = 0;
1.1.1.49! root 14597: REG16(AX) |= 0x8000; // 0025h
1.1.1.24 root 14598: REG16(AX) |= 0x4000; // 0026h
1.1.1.49! root 14599: REG16(AX) |= 0x2000; // 0027h
1.1.1.24 root 14600: // REG16(AX) |= 0x1000; // 0028h
14601: // REG16(AX) |= 0x0800; // 0029h
14602: REG16(AX) |= 0x0400; // 002ah
14603: // REG16(AX) |= 0x0200; // 002bh
14604: // REG16(AX) |= 0x0100; // 002ch
14605: // REG16(AX) |= 0x0080; // 002dh
14606: // REG16(AX) |= 0x0040; // 002eh
14607: REG16(AX) |= 0x0020; // 002fh
14608: // REG16(AX) |= 0x0010; // 0030h
14609: REG16(AX) |= 0x0008; // 0031h
14610: REG16(AX) |= 0x0004; // 0032h
14611: // REG16(AX) |= 0x0002; // 0033h
14612: // REG16(AX) |= 0x0001; // 0034h
14613: }
14614:
1.1.1.49! root 14615: inline void msdos_int_33h_004dh()
! 14616: {
! 14617: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), "Copyright 2017 MS-DOS Player");
! 14618: }
! 14619:
! 14620: inline void msdos_int_33h_006dh()
! 14621: {
! 14622: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x08; // V8.05
! 14623: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = 0x05;
! 14624: }
! 14625:
1.1.1.19 root 14626: inline void msdos_int_67h_40h()
14627: {
14628: if(!support_ems) {
14629: REG8(AH) = 0x84;
14630: } else {
14631: REG8(AH) = 0x00;
14632: }
14633: }
14634:
14635: inline void msdos_int_67h_41h()
14636: {
14637: if(!support_ems) {
14638: REG8(AH) = 0x84;
14639: } else {
14640: REG8(AH) = 0x00;
14641: REG16(BX) = EMS_TOP >> 4;
14642: }
14643: }
14644:
14645: inline void msdos_int_67h_42h()
14646: {
14647: if(!support_ems) {
14648: REG8(AH) = 0x84;
14649: } else {
14650: REG8(AH) = 0x00;
14651: REG16(BX) = free_ems_pages;
14652: REG16(DX) = MAX_EMS_PAGES;
14653: }
14654: }
14655:
14656: inline void msdos_int_67h_43h()
14657: {
14658: if(!support_ems) {
14659: REG8(AH) = 0x84;
14660: } else if(REG16(BX) > MAX_EMS_PAGES) {
14661: REG8(AH) = 0x87;
14662: } else if(REG16(BX) > free_ems_pages) {
14663: REG8(AH) = 0x88;
14664: } else if(REG16(BX) == 0) {
14665: REG8(AH) = 0x89;
14666: } else {
1.1.1.31 root 14667: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14668: if(!ems_handles[i].allocated) {
14669: ems_allocate_pages(i, REG16(BX));
14670: REG8(AH) = 0x00;
14671: REG16(DX) = i;
14672: return;
14673: }
14674: }
14675: REG8(AH) = 0x85;
14676: }
14677: }
14678:
14679: inline void msdos_int_67h_44h()
14680: {
14681: if(!support_ems) {
14682: REG8(AH) = 0x84;
1.1.1.31 root 14683: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14684: REG8(AH) = 0x83;
14685: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
14686: REG8(AH) = 0x8a;
14687: // } else if(!(REG8(AL) < 4)) {
14688: // REG8(AH) = 0x8b;
14689: } else if(REG16(BX) == 0xffff) {
14690: ems_unmap_page(REG8(AL) & 3);
14691: REG8(AH) = 0x00;
14692: } else {
14693: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
14694: REG8(AH) = 0x00;
14695: }
14696: }
14697:
14698: inline void msdos_int_67h_45h()
14699: {
14700: if(!support_ems) {
14701: REG8(AH) = 0x84;
1.1.1.31 root 14702: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14703: REG8(AH) = 0x83;
14704: } else {
14705: ems_release_pages(REG16(DX));
14706: REG8(AH) = 0x00;
14707: }
14708: }
14709:
14710: inline void msdos_int_67h_46h()
14711: {
14712: if(!support_ems) {
14713: REG8(AH) = 0x84;
14714: } else {
1.1.1.29 root 14715: // REG16(AX) = 0x0032; // EMS 3.2
14716: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 14717: }
14718: }
14719:
14720: inline void msdos_int_67h_47h()
14721: {
14722: // NOTE: the map data should be stored in the specified ems page, not process data
14723: process_t *process = msdos_process_info_get(current_psp);
14724:
14725: if(!support_ems) {
14726: REG8(AH) = 0x84;
1.1.1.31 root 14727: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14728: // REG8(AH) = 0x83;
14729: } else if(process->ems_pages_stored) {
14730: REG8(AH) = 0x8d;
14731: } else {
14732: for(int i = 0; i < 4; i++) {
14733: process->ems_pages[i].handle = ems_pages[i].handle;
14734: process->ems_pages[i].page = ems_pages[i].page;
14735: process->ems_pages[i].mapped = ems_pages[i].mapped;
14736: }
14737: process->ems_pages_stored = true;
14738: REG8(AH) = 0x00;
14739: }
14740: }
14741:
14742: inline void msdos_int_67h_48h()
14743: {
14744: // NOTE: the map data should be restored from the specified ems page, not process data
14745: process_t *process = msdos_process_info_get(current_psp);
14746:
14747: if(!support_ems) {
14748: REG8(AH) = 0x84;
1.1.1.31 root 14749: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14750: // REG8(AH) = 0x83;
14751: } else if(!process->ems_pages_stored) {
14752: REG8(AH) = 0x8e;
14753: } else {
14754: for(int i = 0; i < 4; i++) {
14755: if(process->ems_pages[i].mapped) {
14756: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
14757: } else {
14758: ems_unmap_page(i);
14759: }
14760: }
14761: process->ems_pages_stored = false;
14762: REG8(AH) = 0x00;
14763: }
14764: }
14765:
14766: inline void msdos_int_67h_4bh()
14767: {
14768: if(!support_ems) {
14769: REG8(AH) = 0x84;
14770: } else {
14771: REG8(AH) = 0x00;
14772: REG16(BX) = 0;
1.1.1.31 root 14773: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14774: if(ems_handles[i].allocated) {
14775: REG16(BX)++;
14776: }
14777: }
14778: }
14779: }
14780:
14781: inline void msdos_int_67h_4ch()
14782: {
14783: if(!support_ems) {
14784: REG8(AH) = 0x84;
1.1.1.31 root 14785: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14786: REG8(AH) = 0x83;
14787: } else {
14788: REG8(AH) = 0x00;
14789: REG16(BX) = ems_handles[REG16(DX)].pages;
14790: }
14791: }
14792:
14793: inline void msdos_int_67h_4dh()
14794: {
14795: if(!support_ems) {
14796: REG8(AH) = 0x84;
14797: } else {
14798: REG8(AH) = 0x00;
14799: REG16(BX) = 0;
1.1.1.31 root 14800: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14801: if(ems_handles[i].allocated) {
14802: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
14803: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
14804: REG16(BX)++;
14805: }
14806: }
14807: }
14808: }
14809:
1.1.1.20 root 14810: inline void msdos_int_67h_4eh()
14811: {
14812: if(!support_ems) {
14813: REG8(AH) = 0x84;
14814: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
14815: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
14816: // save page map
14817: for(int i = 0; i < 4; i++) {
14818: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
14819: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
14820: }
14821: }
14822: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
14823: // restore page map
14824: for(int i = 0; i < 4; i++) {
14825: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
14826: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
14827:
1.1.1.31 root 14828: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 14829: ems_map_page(i, handle, page);
14830: } else {
14831: ems_unmap_page(i);
14832: }
14833: }
14834: }
14835: REG8(AH) = 0x00;
14836: } else if(REG8(AL) == 0x03) {
14837: REG8(AH) = 0x00;
1.1.1.21 root 14838: REG8(AL) = 4 * 4;
14839: } else {
1.1.1.22 root 14840: 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 14841: REG8(AH) = 0x8f;
14842: }
14843: }
14844:
14845: inline void msdos_int_67h_4fh()
14846: {
14847: if(!support_ems) {
14848: REG8(AH) = 0x84;
14849: } else if(REG8(AL) == 0x00) {
14850: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
14851:
14852: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
14853: for(int i = 0; i < count; i++) {
14854: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
14855: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
14856:
14857: // if(!(physical < 4)) {
14858: // REG8(AH) = 0x8b;
14859: // return;
14860: // }
14861: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
1.1.1.41 root 14862: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].handle : 0xffff;
14863: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
1.1.1.21 root 14864: }
14865: REG8(AH) = 0x00;
14866: } else if(REG8(AL) == 0x01) {
14867: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
14868:
14869: for(int i = 0; i < count; i++) {
14870: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
14871: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
14872: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
14873: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
14874:
14875: // if(!(physical < 4)) {
14876: // REG8(AH) = 0x8b;
14877: // return;
14878: // } else
1.1.1.41 root 14879: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && logical < ems_handles[handle].pages) {
1.1.1.21 root 14880: ems_map_page(physical & 3, handle, logical);
14881: } else {
1.1.1.41 root 14882: ems_unmap_page(physical & 3);
1.1.1.21 root 14883: }
14884: }
14885: REG8(AH) = 0x00;
14886: } else if(REG8(AL) == 0x02) {
14887: REG8(AH) = 0x00;
14888: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 14889: } else {
1.1.1.22 root 14890: 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 14891: REG8(AH) = 0x8f;
14892: }
14893: }
14894:
14895: inline void msdos_int_67h_50h()
14896: {
14897: if(!support_ems) {
14898: REG8(AH) = 0x84;
1.1.1.31 root 14899: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 14900: REG8(AH) = 0x83;
14901: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
14902: for(int i = 0; i < REG16(CX); i++) {
14903: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
14904: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
14905:
14906: if(REG8(AL) == 0x01) {
14907: physical = ((physical << 4) - EMS_TOP) / 0x4000;
14908: }
14909: // if(!(physical < 4)) {
14910: // REG8(AH) = 0x8b;
14911: // return;
14912: // } else
14913: if(logical == 0xffff) {
14914: ems_unmap_page(physical & 3);
14915: } else if(logical < ems_handles[REG16(DX)].pages) {
14916: ems_map_page(physical & 3, REG16(DX), logical);
14917: } else {
14918: REG8(AH) = 0x8a;
14919: return;
14920: }
14921: }
14922: REG8(AH) = 0x00;
14923: } else {
1.1.1.22 root 14924: 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 14925: REG8(AH) = 0x8f;
14926: }
14927: }
14928:
1.1.1.19 root 14929: inline void msdos_int_67h_51h()
14930: {
14931: if(!support_ems) {
14932: REG8(AH) = 0x84;
1.1.1.31 root 14933: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14934: REG8(AH) = 0x83;
14935: } else if(REG16(BX) > MAX_EMS_PAGES) {
14936: REG8(AH) = 0x87;
14937: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
14938: REG8(AH) = 0x88;
14939: } else {
14940: ems_reallocate_pages(REG16(DX), REG16(BX));
14941: REG8(AH) = 0x00;
14942: }
14943: }
14944:
1.1.1.20 root 14945: inline void msdos_int_67h_52h()
14946: {
14947: if(!support_ems) {
14948: REG8(AH) = 0x84;
1.1.1.31 root 14949: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
14950: // REG8(AH) = 0x83;
1.1.1.20 root 14951: } else if(REG8(AL) == 0x00) {
14952: REG8(AL) = 0x00; // handle is volatile
14953: REG8(AH) = 0x00;
14954: } else if(REG8(AL) == 0x01) {
14955: if(REG8(BL) == 0x00) {
14956: REG8(AH) = 0x00;
14957: } else {
14958: REG8(AH) = 0x90; // undefined attribute type
14959: }
14960: } else if(REG8(AL) == 0x02) {
14961: REG8(AL) = 0x00; // only volatile handles supported
14962: REG8(AH) = 0x00;
14963: } else {
1.1.1.22 root 14964: 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 14965: REG8(AH) = 0x8f;
14966: }
14967: }
14968:
1.1.1.19 root 14969: inline void msdos_int_67h_53h()
14970: {
14971: if(!support_ems) {
14972: REG8(AH) = 0x84;
1.1.1.31 root 14973: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14974: REG8(AH) = 0x83;
14975: } else if(REG8(AL) == 0x00) {
14976: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
14977: REG8(AH) = 0x00;
14978: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 14979: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14980: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
14981: REG8(AH) = 0xa1;
14982: return;
14983: }
14984: }
14985: REG8(AH) = 0x00;
14986: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
14987: } else {
1.1.1.22 root 14988: 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 14989: REG8(AH) = 0x8f;
1.1.1.19 root 14990: }
14991: }
14992:
14993: inline void msdos_int_67h_54h()
14994: {
14995: if(!support_ems) {
14996: REG8(AH) = 0x84;
14997: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 14998: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14999: if(ems_handles[i].allocated) {
15000: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
15001: } else {
15002: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
15003: }
15004: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
15005: }
15006: REG8(AH) = 0x00;
15007: REG8(AL) = MAX_EMS_HANDLES;
15008: } else if(REG8(AL) == 0x01) {
15009: REG8(AH) = 0xa0; // not found
1.1.1.31 root 15010: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 15011: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
15012: REG8(AH) = 0x00;
15013: REG16(DX) = i;
15014: break;
15015: }
15016: }
15017: } else if(REG8(AL) == 0x02) {
15018: REG8(AH) = 0x00;
15019: REG16(BX) = MAX_EMS_HANDLES;
15020: } else {
1.1.1.22 root 15021: 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 15022: REG8(AH) = 0x8f;
15023: }
15024: }
15025:
1.1.1.49! root 15026: inline void msdos_int_67h_55h()
! 15027: {
! 15028: if(!support_ems) {
! 15029: REG8(AH) = 0x84;
! 15030: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
! 15031: REG8(AH) = 0x83;
! 15032: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
! 15033: UINT16 jump_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0);
! 15034: UINT16 jump_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2);
! 15035: UINT8 entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4);
! 15036: UINT16 map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
! 15037: UINT16 map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7);
! 15038:
! 15039: for(int i = 0; i < (int)entries; i++) {
! 15040: int logical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 0);
! 15041: int physical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 2);
! 15042:
! 15043: if(REG8(AL) == 0x01) {
! 15044: physical = ((physical << 4) - EMS_TOP) / 0x4000;
! 15045: }
! 15046: // if(!(physical < 4)) {
! 15047: // REG8(AH) = 0x8b;
! 15048: // return;
! 15049: // } else
! 15050: if(logical == 0xffff) {
! 15051: ems_unmap_page(physical & 3);
! 15052: } else if(logical < ems_handles[REG16(DX)].pages) {
! 15053: ems_map_page(physical & 3, REG16(DX), logical);
! 15054: } else {
! 15055: REG8(AH) = 0x8a;
! 15056: return;
! 15057: }
! 15058: }
! 15059: i386_jmp_far(jump_seg, jump_ofs);
! 15060: REG8(AH) = 0x00;
! 15061: } else {
! 15062: 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));
! 15063: REG8(AH) = 0x8f;
! 15064: }
! 15065: }
! 15066:
! 15067: inline void msdos_int_67h_56h()
! 15068: {
! 15069: if(!support_ems) {
! 15070: REG8(AH) = 0x84;
! 15071: } else if(REG8(AL) == 0x02) {
! 15072: REG16(BX) = (2 + 2) * 4;
! 15073: REG8(AH) = 0x00;
! 15074: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
! 15075: REG8(AH) = 0x83;
! 15076: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
! 15077: UINT16 call_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0);
! 15078: UINT16 call_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2);
! 15079: UINT8 new_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4);
! 15080: UINT16 new_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
! 15081: UINT16 new_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7);
! 15082: #if 0
! 15083: UINT8 old_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 9);
! 15084: UINT16 old_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 10);
! 15085: UINT16 old_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 12);
! 15086: #endif
! 15087: UINT16 handles[4], pages[4];
! 15088:
! 15089: // alter page map and call routine is at fffc:001f
! 15090: if(!(call_seg == 0 && call_ofs == 0)) {
! 15091: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far
! 15092: mem[DUMMY_TOP + 0x20] = (call_ofs >> 0) & 0xff;
! 15093: mem[DUMMY_TOP + 0x21] = (call_ofs >> 8) & 0xff;
! 15094: mem[DUMMY_TOP + 0x22] = (call_seg >> 0) & 0xff;
! 15095: mem[DUMMY_TOP + 0x23] = (call_seg >> 8) & 0xff;
! 15096: } else {
! 15097: // invalid call addr :-(
! 15098: mem[DUMMY_TOP + 0x1f] = 0x90; // nop
! 15099: mem[DUMMY_TOP + 0x20] = 0x90; // nop
! 15100: mem[DUMMY_TOP + 0x21] = 0x90; // nop
! 15101: mem[DUMMY_TOP + 0x22] = 0x90; // nop
! 15102: mem[DUMMY_TOP + 0x23] = 0x90; // nop
! 15103: }
! 15104: // do call far (push cs/ip) in old mapping
! 15105: i386_call_far(DUMMY_TOP >> 4, 0x001f);
! 15106:
! 15107: // get old mapping data
! 15108: #if 0
! 15109: for(int i = 0; i < (int)old_entries; i++) {
! 15110: int logical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 0);
! 15111: int physical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 2);
! 15112:
! 15113: if(REG8(AL) == 0x01) {
! 15114: physical = ((physical << 4) - EMS_TOP) / 0x4000;
! 15115: }
! 15116: // if(!(physical < 4)) {
! 15117: // REG8(AH) = 0x8b;
! 15118: // return;
! 15119: // } else
! 15120: if(logical == 0xffff) {
! 15121: ems_unmap_page(physical & 3);
! 15122: } else if(logical < ems_handles[REG16(DX)].pages) {
! 15123: ems_map_page(physical & 3, REG16(DX), logical);
! 15124: } else {
! 15125: REG8(AH) = 0x8a;
! 15126: return;
! 15127: }
! 15128: }
! 15129: #endif
! 15130: for(int i = 0; i < 4; i++) {
! 15131: handles[i] = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
! 15132: pages [i] = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
! 15133: }
! 15134:
! 15135: // set new mapping
! 15136: for(int i = 0; i < (int)new_entries; i++) {
! 15137: int logical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 0);
! 15138: int physical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 2);
! 15139:
! 15140: if(REG8(AL) == 0x01) {
! 15141: physical = ((physical << 4) - EMS_TOP) / 0x4000;
! 15142: }
! 15143: // if(!(physical < 4)) {
! 15144: // REG8(AH) = 0x8b;
! 15145: // return;
! 15146: // } else
! 15147: if(logical == 0xffff) {
! 15148: ems_unmap_page(physical & 3);
! 15149: } else if(logical < ems_handles[REG16(DX)].pages) {
! 15150: ems_map_page(physical & 3, REG16(DX), logical);
! 15151: } else {
! 15152: REG8(AH) = 0x8a;
! 15153: return;
! 15154: }
! 15155: }
! 15156:
! 15157: // push old mapping data in new mapping
! 15158: for(int i = 0; i < 4; i++) {
! 15159: i386_push16(handles[i]);
! 15160: i386_push16(pages [i]);
! 15161: }
! 15162: REG8(AH) = 0x00;
! 15163: } else {
! 15164: 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));
! 15165: REG8(AH) = 0x8f;
! 15166: }
! 15167: }
! 15168:
1.1.1.20 root 15169: inline void msdos_int_67h_57h_tmp()
15170: {
15171: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
15172: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
15173: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
15174: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
15175: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
15176: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
15177: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
15178: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
15179: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
15180:
1.1.1.32 root 15181: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 15182: UINT32 src_addr, dest_addr;
15183: UINT32 src_addr_max, dest_addr_max;
15184:
15185: if(src_type == 0) {
15186: src_buffer = mem;
15187: src_addr = (src_seg << 4) + src_ofs;
15188: src_addr_max = MAX_MEM;
15189: } else {
1.1.1.31 root 15190: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 15191: REG8(AH) = 0x83;
15192: return;
15193: } else if(!(src_seg < ems_handles[src_handle].pages)) {
15194: REG8(AH) = 0x8a;
15195: return;
15196: }
1.1.1.32 root 15197: if(ems_handles[src_handle].buffer != NULL) {
15198: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
15199: }
1.1.1.20 root 15200: src_addr = src_ofs;
1.1.1.32 root 15201: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 15202: }
15203: if(dest_type == 0) {
15204: dest_buffer = mem;
15205: dest_addr = (dest_seg << 4) + dest_ofs;
15206: dest_addr_max = MAX_MEM;
15207: } else {
1.1.1.31 root 15208: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 15209: REG8(AH) = 0x83;
15210: return;
15211: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
15212: REG8(AH) = 0x8a;
15213: return;
15214: }
1.1.1.32 root 15215: if(ems_handles[dest_handle].buffer != NULL) {
15216: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
15217: }
1.1.1.20 root 15218: dest_addr = dest_ofs;
1.1.1.32 root 15219: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 15220: }
1.1.1.32 root 15221: if(src_buffer != NULL && dest_buffer != NULL) {
15222: for(int i = 0; i < copy_length; i++) {
15223: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
15224: if(REG8(AL) == 0x00) {
15225: dest_buffer[dest_addr++] = src_buffer[src_addr++];
15226: } else if(REG8(AL) == 0x01) {
15227: UINT8 tmp = dest_buffer[dest_addr];
15228: dest_buffer[dest_addr++] = src_buffer[src_addr];
15229: src_buffer[src_addr++] = tmp;
15230: }
15231: } else {
15232: REG8(AH) = 0x93;
15233: return;
1.1.1.20 root 15234: }
15235: }
1.1.1.32 root 15236: REG8(AH) = 0x00;
15237: } else {
15238: REG8(AH) = 0x80;
1.1.1.20 root 15239: }
15240: }
15241:
15242: inline void msdos_int_67h_57h()
15243: {
15244: if(!support_ems) {
15245: REG8(AH) = 0x84;
15246: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
15247: struct {
15248: UINT16 handle;
15249: UINT16 page;
15250: bool mapped;
15251: } tmp_pages[4];
15252:
15253: // unmap pages to copy memory data to ems buffer
15254: for(int i = 0; i < 4; i++) {
15255: tmp_pages[i].handle = ems_pages[i].handle;
15256: tmp_pages[i].page = ems_pages[i].page;
15257: tmp_pages[i].mapped = ems_pages[i].mapped;
15258: ems_unmap_page(i);
15259: }
15260:
15261: // run move/exchange operation
15262: msdos_int_67h_57h_tmp();
15263:
15264: // restore unmapped pages
15265: for(int i = 0; i < 4; i++) {
15266: if(tmp_pages[i].mapped) {
15267: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
15268: }
15269: }
15270: } else {
1.1.1.22 root 15271: 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 15272: REG8(AH) = 0x8f;
15273: }
15274: }
15275:
15276: inline void msdos_int_67h_58h()
15277: {
15278: if(!support_ems) {
15279: REG8(AH) = 0x84;
15280: } else if(REG8(AL) == 0x00) {
15281: for(int i = 0; i < 4; i++) {
1.1.1.30 root 15282: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
15283: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 15284: }
15285: REG8(AH) = 0x00;
15286: REG16(CX) = 4;
15287: } else if(REG8(AL) == 0x01) {
15288: REG8(AH) = 0x00;
15289: REG16(CX) = 4;
15290: } else {
1.1.1.22 root 15291: 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 15292: REG8(AH) = 0x8f;
15293: }
15294: }
15295:
1.1.1.42 root 15296: inline void msdos_int_67h_59h()
15297: {
15298: if(!support_ems) {
15299: REG8(AH) = 0x84;
15300: } else if(REG8(AL) == 0x00) {
1.1.1.49! root 15301: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1024;
! 15302: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 0;
! 15303: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 4 * 4;
! 15304: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = 0;
! 15305: REG8(AH) = 0x00;
! 15306: // REG8(AH) = 0xa4; // access denied by operating system
1.1.1.42 root 15307: } else if(REG8(AL) == 0x01) {
15308: REG8(AH) = 0x00;
15309: REG16(BX) = free_ems_pages;
15310: REG16(DX) = MAX_EMS_PAGES;
15311: } else {
15312: 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));
15313: REG8(AH) = 0x8f;
15314: }
15315: }
15316:
1.1.1.20 root 15317: inline void msdos_int_67h_5ah()
15318: {
15319: if(!support_ems) {
1.1.1.19 root 15320: REG8(AH) = 0x84;
1.1.1.20 root 15321: } else if(REG16(BX) > MAX_EMS_PAGES) {
15322: REG8(AH) = 0x87;
15323: } else if(REG16(BX) > free_ems_pages) {
15324: REG8(AH) = 0x88;
15325: // } else if(REG16(BX) == 0) {
15326: // REG8(AH) = 0x89;
15327: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 15328: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 15329: if(!ems_handles[i].allocated) {
15330: ems_allocate_pages(i, REG16(BX));
15331: REG8(AH) = 0x00;
15332: REG16(DX) = i;
15333: return;
15334: }
15335: }
15336: REG8(AH) = 0x85;
15337: } else {
1.1.1.22 root 15338: 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 15339: REG8(AH) = 0x8f;
1.1.1.19 root 15340: }
15341: }
15342:
1.1.1.49! root 15343: inline void msdos_int_67h_5bh()
! 15344: {
! 15345: static UINT8 stored_bl = 0x00;
! 15346: static UINT16 stored_es = 0x0000;
! 15347: static UINT16 stored_di = 0x0000;
! 15348:
! 15349: if(!support_ems) {
! 15350: REG8(AH) = 0x84;
! 15351: } else if(REG8(AL) == 0x00) {
! 15352: if(stored_bl == 0x00) {
! 15353: if(!(stored_es == 0 && stored_di == 0)) {
! 15354: for(int i = 0; i < 4; i++) {
! 15355: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
! 15356: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
! 15357: }
! 15358: }
! 15359: SREG(ES) = stored_es;
! 15360: i386_load_segment_descriptor(ES);
! 15361: REG16(DI) = stored_di;
! 15362: } else {
! 15363: REG8(BL) = stored_bl;
! 15364: }
! 15365: REG8(AH) = 0x00;
! 15366: } else if(REG8(AL) == 0x01) {
! 15367: if(REG8(BL) == 0x00) {
! 15368: if(!(SREG(ES) == 0 && REG16(DI) == 0)) {
! 15369: for(int i = 0; i < 4; i++) {
! 15370: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0);
! 15371: UINT16 page = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2);
! 15372:
! 15373: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
! 15374: ems_map_page(i, handle, page);
! 15375: } else {
! 15376: ems_unmap_page(i);
! 15377: }
! 15378: }
! 15379: }
! 15380: }
! 15381: stored_bl = REG8(BL);
! 15382: stored_es = SREG(ES);
! 15383: stored_di = REG16(DI);
! 15384: REG8(AH) = 0x00;
! 15385: } else if(REG8(AL) == 0x02) {
! 15386: REG16(DX) = 4 * 4;
! 15387: REG8(AH) = 0x00;
! 15388: } else if(REG8(AL) == 0x03) {
! 15389: REG8(BL) = 0x00; // not supported
! 15390: REG8(AH) = 0x00;
! 15391: } else if(REG8(AL) == 0x04) {
! 15392: REG8(AH) = 0x00;
! 15393: } else if(REG8(AL) == 0x05) {
! 15394: REG8(BL) = 0x00; // not supported
! 15395: REG8(AH) = 0x00;
! 15396: } else {
! 15397: 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));
! 15398: REG8(AH) = 0x8f;
! 15399: }
! 15400: }
! 15401:
1.1.1.43 root 15402: inline void msdos_int_67h_5dh()
15403: {
15404: if(!support_ems) {
15405: REG8(AH) = 0x84;
15406: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
15407: REG8(AH) = 0xa4; // operating system denied access
15408: } else {
15409: 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));
15410: REG8(AH) = 0x8f;
15411: }
15412: }
15413:
1.1.1.49! root 15414: inline void msdos_int_67h_70h()
! 15415: {
! 15416: if(!support_ems) {
! 15417: REG8(AH) = 0x84;
! 15418: } else if(REG8(AL) == 0x00) {
! 15419: REG8(AL) = 0x00;
! 15420: REG8(AH) = 0x00;
! 15421: } else if(REG8(AL) == 0x01) {
! 15422: REG8(AL) = 0x00;
! 15423: // REG8(AH) = (REG8(BL) == 0x00) ? 0x00 : 0x80;
! 15424: REG8(AH) = 0x00;
! 15425: } else {
! 15426: 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));
! 15427: REG8(AH) = 0x8f;
! 15428: }
! 15429: }
! 15430:
1.1.1.30 root 15431: inline void msdos_int_67h_deh()
15432: {
15433: REG8(AH) = 0x84;
15434: }
15435:
1.1.1.19 root 15436: #ifdef SUPPORT_XMS
15437:
1.1.1.32 root 15438: void msdos_xms_init()
1.1.1.26 root 15439: {
1.1.1.30 root 15440: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
15441: emb_handle_top->address = EMB_TOP;
15442: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 15443: xms_a20_local_enb_count = 0;
15444: }
15445:
1.1.1.32 root 15446: void msdos_xms_finish()
15447: {
15448: msdos_xms_release();
15449: }
15450:
15451: void msdos_xms_release()
1.1.1.30 root 15452: {
15453: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
15454: emb_handle_t *next_handle = emb_handle->next;
15455: free(emb_handle);
15456: emb_handle = next_handle;
15457: }
15458: }
15459:
15460: emb_handle_t *msdos_xms_get_emb_handle(int handle)
15461: {
15462: if(handle != 0) {
15463: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15464: if(emb_handle->handle == handle) {
15465: return(emb_handle);
15466: }
15467: }
15468: }
15469: return(NULL);
15470: }
15471:
15472: int msdos_xms_get_unused_emb_handle_id()
15473: {
15474: for(int handle = 1;; handle++) {
15475: if(msdos_xms_get_emb_handle(handle) == NULL) {
15476: return(handle);
15477: }
15478: }
15479: return(0);
15480: }
15481:
15482: int msdos_xms_get_unused_emb_handle_count()
15483: {
15484: int count = 64; //255;
15485:
15486: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15487: if(emb_handle->handle != 0) {
15488: if(--count == 1) {
15489: break;
15490: }
15491: }
15492: }
15493: return(count);
15494: }
15495:
15496: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
15497: {
15498: if(emb_handle->size_kb > size_kb) {
15499: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
15500:
15501: new_handle->address = emb_handle->address + size_kb * 1024;
15502: new_handle->size_kb = emb_handle->size_kb - size_kb;
15503: emb_handle->size_kb = size_kb;
15504:
15505: new_handle->prev = emb_handle;
15506: new_handle->next = emb_handle->next;
15507: if(emb_handle->next != NULL) {
15508: emb_handle->next->prev = new_handle;
15509: }
15510: emb_handle->next = new_handle;
15511: }
15512: }
15513:
15514: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
15515: {
15516: emb_handle_t *next_handle = emb_handle->next;
15517:
15518: if(next_handle != NULL) {
15519: emb_handle->size_kb += next_handle->size_kb;
15520:
15521: if(next_handle->next != NULL) {
15522: next_handle->next->prev = emb_handle;
15523: }
15524: emb_handle->next = next_handle->next;
15525: free(next_handle);
15526: }
15527: }
15528:
15529: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
15530: {
15531: emb_handle_t *target_handle = NULL;
15532:
15533: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15534: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
15535: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
15536: target_handle = emb_handle;
15537: }
15538: }
15539: }
15540: if(target_handle != NULL) {
15541: if(target_handle->size_kb > size_kb) {
15542: msdos_xms_split_emb_handle(target_handle, size_kb);
15543: }
15544: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
15545: return(target_handle);
15546: }
15547: return(NULL);
15548: }
15549:
15550: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
15551: {
15552: emb_handle_t *prev_handle = emb_handle->prev;
15553: emb_handle_t *next_handle = emb_handle->next;
15554:
15555: if(prev_handle != NULL && prev_handle->handle == 0) {
15556: msdos_xms_combine_emb_handles(prev_handle);
15557: emb_handle = prev_handle;
15558: }
15559: if(next_handle != NULL && next_handle->handle == 0) {
15560: msdos_xms_combine_emb_handles(emb_handle);
15561: }
15562: emb_handle->handle = 0;
15563: }
15564:
1.1.1.19 root 15565: inline void msdos_call_xms_00h()
15566: {
1.1.1.29 root 15567: #if defined(HAS_I386)
15568: REG16(AX) = 0x0300; // V3.00 (XMS Version)
1.1.1.45 root 15569: // REG16(BX) = 0x0395; // V3.95 (Driver Revision in BCD)
1.1.1.29 root 15570: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
15571: #else
15572: REG16(AX) = 0x0200; // V2.00 (XMS Version)
15573: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
15574: #endif
15575: // REG16(DX) = 0x0000; // HMA does not exist
15576: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 15577: }
15578:
15579: inline void msdos_call_xms_01h()
15580: {
1.1.1.29 root 15581: if(REG8(AL) == 0x40) {
15582: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
15583: // DX=KB free extended memory returned by last call of function 08h
15584: REG16(AX) = 0x0000;
15585: REG8(BL) = 0x91;
15586: REG16(DX) = xms_dx_after_call_08h;
15587: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
15588: REG16(AX) = 0x0000;
15589: REG8(BL) = 0x81; // Vdisk was detected
15590: #ifdef SUPPORT_HMA
15591: } else if(is_hma_used_by_int_2fh) {
15592: REG16(AX) = 0x0000;
15593: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
15594: } else if(is_hma_used_by_xms) {
15595: REG16(AX) = 0x0000;
15596: REG8(BL) = 0x91; // HMA is already in use
15597: } else {
15598: REG16(AX) = 0x0001;
15599: is_hma_used_by_xms = true;
15600: #else
15601: } else {
15602: REG16(AX) = 0x0000;
15603: REG8(BL) = 0x91; // HMA is already in use
15604: #endif
15605: }
1.1.1.19 root 15606: }
15607:
15608: inline void msdos_call_xms_02h()
15609: {
1.1.1.29 root 15610: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
15611: REG16(AX) = 0x0000;
15612: REG8(BL) = 0x81; // Vdisk was detected
15613: #ifdef SUPPORT_HMA
15614: } else if(is_hma_used_by_int_2fh) {
15615: REG16(AX) = 0x0000;
15616: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
15617: } else if(!is_hma_used_by_xms) {
15618: REG16(AX) = 0x0000;
15619: REG8(BL) = 0x93; // HMA is not allocated
15620: } else {
15621: REG16(AX) = 0x0001;
15622: is_hma_used_by_xms = false;
15623: // restore first free mcb in high memory area
15624: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
15625: #else
15626: } else {
15627: REG16(AX) = 0x0000;
15628: REG8(BL) = 0x91; // HMA is already in use
15629: #endif
15630: }
1.1.1.19 root 15631: }
15632:
15633: inline void msdos_call_xms_03h()
15634: {
15635: i386_set_a20_line(1);
15636: REG16(AX) = 0x0001;
15637: REG8(BL) = 0x00;
15638: }
15639:
15640: inline void msdos_call_xms_04h()
15641: {
1.1.1.21 root 15642: i386_set_a20_line(0);
15643: REG16(AX) = 0x0001;
15644: REG8(BL) = 0x00;
1.1.1.19 root 15645: }
15646:
15647: inline void msdos_call_xms_05h()
15648: {
15649: i386_set_a20_line(1);
15650: REG16(AX) = 0x0001;
15651: REG8(BL) = 0x00;
1.1.1.21 root 15652: xms_a20_local_enb_count++;
1.1.1.19 root 15653: }
15654:
15655: void msdos_call_xms_06h()
15656: {
1.1.1.21 root 15657: if(xms_a20_local_enb_count > 0) {
1.1.1.45 root 15658: if(--xms_a20_local_enb_count == 0) {
15659: i386_set_a20_line(0);
15660: REG16(AX) = 0x0001;
15661: REG8(BL) = 0x00;
15662: } else {
15663: REG16(AX) = 0x0000;
15664: REG8(BL) = 0x94;
15665: }
1.1.1.21 root 15666: } else {
1.1.1.45 root 15667: i386_set_a20_line(0);
1.1.1.21 root 15668: REG16(AX) = 0x0001;
15669: REG8(BL) = 0x00;
1.1.1.19 root 15670: }
15671: }
15672:
15673: inline void msdos_call_xms_07h()
15674: {
15675: REG16(AX) = (m_a20_mask >> 20) & 1;
15676: REG8(BL) = 0x00;
15677: }
15678:
15679: inline void msdos_call_xms_08h()
15680: {
1.1.1.45 root 15681: UINT32 eax = 0, edx = 0;
1.1.1.19 root 15682:
1.1.1.30 root 15683: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15684: if(emb_handle->handle == 0) {
1.1.1.45 root 15685: if(eax < emb_handle->size_kb) {
15686: eax = emb_handle->size_kb;
1.1.1.19 root 15687: }
1.1.1.45 root 15688: edx += emb_handle->size_kb;
1.1.1.19 root 15689: }
15690: }
1.1.1.45 root 15691: if(eax > 65535) {
15692: eax = 65535;
15693: }
15694: if(edx > 65535) {
15695: edx = 65535;
15696: }
15697: if(eax == 0 && edx == 0) {
1.1.1.19 root 15698: REG8(BL) = 0xa0;
15699: } else {
15700: REG8(BL) = 0x00;
15701: }
1.1.1.45 root 15702: #if defined(HAS_I386)
15703: REG32(EAX) = eax;
15704: REG32(EDX) = edx;
15705: #else
15706: REG16(AX) = (UINT16)eax;
15707: REG16(DX) = (UINT16)edx;
15708: #endif
1.1.1.29 root 15709: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 15710: }
15711:
1.1.1.30 root 15712: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 15713: {
1.1.1.30 root 15714: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
15715:
15716: if(emb_handle != NULL) {
15717: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
15718:
15719: REG16(AX) = 0x0001;
15720: REG16(DX) = emb_handle->handle;
15721: REG8(BL) = 0x00;
15722: } else {
15723: REG16(AX) = REG16(DX) = 0x0000;
15724: REG8(BL) = 0xa0;
1.1.1.19 root 15725: }
1.1.1.30 root 15726: }
15727:
15728: inline void msdos_call_xms_09h()
15729: {
15730: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 15731: }
15732:
15733: inline void msdos_call_xms_0ah()
15734: {
1.1.1.30 root 15735: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15736:
15737: if(emb_handle == NULL) {
1.1.1.19 root 15738: REG16(AX) = 0x0000;
15739: REG8(BL) = 0xa2;
1.1.1.45 root 15740: // } else if(emb_handle->lock > 0) {
15741: // REG16(AX) = 0x0000;
15742: // REG8(BL) = 0xab;
1.1.1.19 root 15743: } else {
1.1.1.30 root 15744: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 15745:
15746: REG16(AX) = 0x0001;
15747: REG8(BL) = 0x00;
15748: }
15749: }
15750:
15751: inline void msdos_call_xms_0bh()
15752: {
15753: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
15754: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
15755: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
15756: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
15757: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
15758:
15759: UINT8 *src_buffer, *dest_buffer;
15760: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 15761: emb_handle_t *emb_handle;
1.1.1.19 root 15762:
15763: if(src_handle == 0) {
15764: src_buffer = mem;
15765: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
15766: src_addr_max = MAX_MEM;
15767: } else {
1.1.1.30 root 15768: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 15769: REG16(AX) = 0x0000;
15770: REG8(BL) = 0xa3;
15771: return;
15772: }
1.1.1.30 root 15773: src_buffer = mem + emb_handle->address;
15774: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 15775: }
15776: if(dest_handle == 0) {
15777: dest_buffer = mem;
15778: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
15779: dest_addr_max = MAX_MEM;
15780: } else {
1.1.1.30 root 15781: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 15782: REG16(AX) = 0x0000;
15783: REG8(BL) = 0xa5;
15784: return;
15785: }
1.1.1.30 root 15786: dest_buffer = mem + emb_handle->address;
15787: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 15788: }
15789: for(int i = 0; i < copy_length; i++) {
15790: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
15791: dest_buffer[dest_addr++] = src_buffer[src_addr++];
15792: } else {
15793: break;
15794: }
15795: }
15796: REG16(AX) = 0x0001;
15797: REG8(BL) = 0x00;
15798: }
15799:
15800: inline void msdos_call_xms_0ch()
15801: {
1.1.1.30 root 15802: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15803:
15804: if(emb_handle == NULL) {
1.1.1.19 root 15805: REG16(AX) = 0x0000;
15806: REG8(BL) = 0xa2;
15807: } else {
1.1.1.45 root 15808: if(emb_handle->lock < 255) {
15809: emb_handle->lock++;
15810: }
1.1.1.19 root 15811: REG16(AX) = 0x0001;
1.1.1.30 root 15812: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
15813: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 15814: }
15815: }
15816:
15817: inline void msdos_call_xms_0dh()
15818: {
1.1.1.30 root 15819: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15820:
15821: if(emb_handle == NULL) {
1.1.1.19 root 15822: REG16(AX) = 0x0000;
15823: REG8(BL) = 0xa2;
1.1.1.30 root 15824: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 15825: REG16(AX) = 0x0000;
15826: REG8(BL) = 0xaa;
15827: } else {
1.1.1.30 root 15828: emb_handle->lock--;
1.1.1.19 root 15829: REG16(AX) = 0x0001;
15830: REG8(BL) = 0x00;
15831: }
15832: }
15833:
15834: inline void msdos_call_xms_0eh()
15835: {
1.1.1.30 root 15836: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15837:
15838: if(emb_handle == NULL) {
1.1.1.19 root 15839: REG16(AX) = 0x0000;
15840: REG8(BL) = 0xa2;
15841: } else {
15842: REG16(AX) = 0x0001;
1.1.1.30 root 15843: REG8(BH) = emb_handle->lock;
15844: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
15845: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 15846: }
15847: }
15848:
1.1.1.30 root 15849: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 15850: {
1.1.1.30 root 15851: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15852:
15853: if(emb_handle == NULL) {
1.1.1.19 root 15854: REG16(AX) = 0x0000;
15855: REG8(BL) = 0xa2;
1.1.1.30 root 15856: } else if(emb_handle->lock > 0) {
1.1.1.19 root 15857: REG16(AX) = 0x0000;
15858: REG8(BL) = 0xab;
15859: } else {
1.1.1.30 root 15860: if(emb_handle->size_kb < size_kb) {
15861: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
15862: msdos_xms_combine_emb_handles(emb_handle);
15863: if(emb_handle->size_kb > size_kb) {
15864: msdos_xms_split_emb_handle(emb_handle, size_kb);
15865: }
15866: } else {
15867: int old_handle = emb_handle->handle;
15868: int old_size_kb = emb_handle->size_kb;
15869: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
15870:
15871: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
15872: msdos_xms_free_emb_handle(emb_handle);
15873:
15874: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
15875: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
15876: }
15877: emb_handle->handle = old_handle;
15878: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
15879: free(buffer);
15880: }
15881: } else if(emb_handle->size_kb > size_kb) {
15882: msdos_xms_split_emb_handle(emb_handle, size_kb);
15883: }
15884: if(emb_handle->size_kb != size_kb) {
15885: REG16(AX) = 0x0000;
15886: REG8(BL) = 0xa0;
15887: } else {
15888: REG16(AX) = 0x0001;
15889: REG8(BL) = 0x00;
15890: }
1.1.1.19 root 15891: }
15892: }
15893:
1.1.1.30 root 15894: inline void msdos_call_xms_0fh()
15895: {
15896: msdos_call_xms_0fh(REG16(BX));
15897: }
15898:
1.1.1.19 root 15899: inline void msdos_call_xms_10h()
15900: {
15901: int seg;
15902:
15903: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
15904: REG16(AX) = 0x0001;
15905: REG16(BX) = seg;
15906: } else {
15907: REG16(AX) = 0x0000;
15908: REG8(BL) = 0xb0;
15909: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
15910: }
15911: }
15912:
15913: inline void msdos_call_xms_11h()
15914: {
15915: int mcb_seg = REG16(DX) - 1;
15916: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
15917:
15918: if(mcb->mz == 'M' || mcb->mz == 'Z') {
15919: msdos_mem_free(REG16(DX));
15920: REG16(AX) = 0x0001;
15921: REG8(BL) = 0x00;
15922: } else {
15923: REG16(AX) = 0x0000;
15924: REG8(BL) = 0xb2;
15925: }
15926: }
15927:
15928: inline void msdos_call_xms_12h()
15929: {
15930: int mcb_seg = REG16(DX) - 1;
15931: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
15932: int max_paragraphs;
15933:
15934: if(mcb->mz == 'M' || mcb->mz == 'Z') {
15935: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
15936: REG16(AX) = 0x0001;
15937: REG8(BL) = 0x00;
15938: } else {
15939: REG16(AX) = 0x0000;
15940: REG8(BL) = 0xb0;
15941: REG16(DX) = max_paragraphs;
15942: }
15943: } else {
15944: REG16(AX) = 0x0000;
15945: REG8(BL) = 0xb2;
15946: }
15947: }
15948:
1.1.1.29 root 15949: #if defined(HAS_I386)
15950:
15951: inline void msdos_call_xms_88h()
15952: {
15953: REG32(EAX) = REG32(EDX) = 0x0000;
15954:
1.1.1.30 root 15955: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15956: if(emb_handle->handle == 0) {
15957: if(REG32(EAX) < emb_handle->size_kb) {
15958: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 15959: }
1.1.1.30 root 15960: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 15961: }
15962: }
15963: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
15964: REG8(BL) = 0xa0;
15965: } else {
15966: REG8(BL) = 0x00;
15967: }
15968: REG32(ECX) = EMB_END - 1;
15969: }
15970:
15971: inline void msdos_call_xms_89h()
15972: {
1.1.1.30 root 15973: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 15974: }
15975:
15976: inline void msdos_call_xms_8eh()
15977: {
1.1.1.30 root 15978: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15979:
15980: if(emb_handle == NULL) {
1.1.1.29 root 15981: REG16(AX) = 0x0000;
15982: REG8(BL) = 0xa2;
15983: } else {
15984: REG16(AX) = 0x0001;
1.1.1.30 root 15985: REG8(BH) = emb_handle->lock;
15986: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
15987: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 15988: }
15989: }
15990:
15991: inline void msdos_call_xms_8fh()
15992: {
1.1.1.30 root 15993: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 15994: }
15995:
15996: #endif
1.1.1.19 root 15997: #endif
15998:
1.1.1.26 root 15999: UINT16 msdos_get_equipment()
16000: {
16001: static UINT16 equip = 0;
16002:
16003: if(equip == 0) {
16004: #ifdef SUPPORT_FPU
16005: equip |= (1 << 1); // 80x87 coprocessor installed
16006: #endif
16007: equip |= (1 << 2); // pointing device installed (PS/2)
16008: equip |= (2 << 4); // initial video mode (80x25 color)
16009: // equip |= (1 << 8); // 0 if DMA installed
16010: equip |= (2 << 9); // number of serial ports
16011: 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 16012:
16013: // check only A: and B: if it is floppy drive
16014: int n = 0;
16015: for(int i = 0; i < 2; i++) {
1.1.1.44 root 16016: if(msdos_is_valid_drive(i) && msdos_is_removable_drive(i)) {
16017: n++;
1.1.1.28 root 16018: }
16019: }
16020: if(n != 0) {
16021: equip |= (1 << 0); // floppy disk(s) installed
16022: n--;
16023: equip |= (n << 6); // number of floppies installed less 1
16024: }
16025: // if(joyGetNumDevs() != 0) {
16026: // equip |= (1 << 12); // game port installed
16027: // }
1.1.1.26 root 16028: }
16029: return(equip);
16030: }
16031:
1.1 root 16032: void msdos_syscall(unsigned num)
16033: {
1.1.1.22 root 16034: #ifdef ENABLE_DEBUG_SYSCALL
1.1.1.43 root 16035: if(num == 0x08 || num == 0x1c) {
16036: // don't log the timer interrupts
1.1.1.45 root 16037: // 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.43 root 16038: } else if(num == 0x68) {
1.1.1.22 root 16039: // dummy interrupt for EMS (int 67h)
1.1.1.33 root 16040: 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 16041: } else if(num == 0x69) {
16042: // dummy interrupt for XMS (call far)
1.1.1.33 root 16043: 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.46 root 16044: } else if(num >= 0x6a && num < 0x6f) {
1.1.1.45 root 16045: // dummy interrupt
1.1.1.46 root 16046: } else if(num == 0x6f) {
16047: // dummy interrupt for call 0005h (call near)
16048: fprintf(fp_debug_log, "call 0005h (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.22 root 16049: } else {
1.1.1.33 root 16050: 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 16051: }
16052: #endif
1.1.1.36 root 16053: // update cursor position
16054: if(cursor_moved) {
16055: pcbios_update_cursor_position();
16056: cursor_moved = false;
16057: }
1.1.1.33 root 16058: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
1.1.1.22 root 16059:
1.1 root 16060: switch(num) {
16061: case 0x00:
1.1.1.28 root 16062: try {
16063: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16064: error("division by zero\n");
16065: } catch(...) {
16066: fatalerror("division by zero detected, and failed to terminate current process\n");
16067: }
1.1 root 16068: break;
16069: case 0x04:
1.1.1.28 root 16070: try {
16071: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16072: error("overflow\n");
16073: } catch(...) {
16074: fatalerror("overflow detected, and failed to terminate current process\n");
16075: }
1.1 root 16076: break;
16077: case 0x06:
16078: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 16079: if(!ignore_illegal_insn) {
1.1.1.28 root 16080: try {
16081: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16082: error("illegal instruction\n");
16083: } catch(...) {
16084: fatalerror("illegal instruction detected, and failed to terminate current process\n");
16085: }
1.1.1.14 root 16086: } else {
16087: #if defined(HAS_I386)
1.1.1.39 root 16088: m_eip = m_int6h_skip_eip;
16089: #elif defined(HAS_I286)
16090: m_pc = m_int6h_skip_pc;
1.1.1.14 root 16091: #else
1.1.1.39 root 16092: // 8086/80186 ignore an invalid opcode
1.1.1.14 root 16093: #endif
16094: }
1.1 root 16095: break;
1.1.1.33 root 16096: case 0x09:
16097: // ctrl-break is pressed
16098: if(raise_int_1bh) {
16099: #if defined(HAS_I386)
16100: m_ext = 0; // not an external interrupt
16101: i386_trap(0x1b, 1, 0);
16102: m_ext = 1;
16103: #else
16104: PREFIX86(_interrupt)(0x1b);
16105: #endif
16106: raise_int_1bh = false;
16107: }
1.1.1.8 root 16108: case 0x08:
1.1.1.14 root 16109: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 16110: case 0x0b:
16111: case 0x0c:
16112: case 0x0d:
16113: case 0x0e:
16114: case 0x0f:
16115: // EOI
16116: pic[0].isr &= ~(1 << (num - 0x08));
16117: pic_update();
16118: break;
1.1 root 16119: case 0x10:
16120: // PC BIOS - Video
1.1.1.14 root 16121: if(!restore_console_on_exit) {
1.1.1.15 root 16122: change_console_size(scr_width, scr_height);
1.1 root 16123: }
1.1.1.3 root 16124: m_CF = 0;
1.1 root 16125: switch(REG8(AH)) {
1.1.1.16 root 16126: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 16127: case 0x01: pcbios_int_10h_01h(); break;
16128: case 0x02: pcbios_int_10h_02h(); break;
16129: case 0x03: pcbios_int_10h_03h(); break;
16130: case 0x05: pcbios_int_10h_05h(); break;
16131: case 0x06: pcbios_int_10h_06h(); break;
16132: case 0x07: pcbios_int_10h_07h(); break;
16133: case 0x08: pcbios_int_10h_08h(); break;
16134: case 0x09: pcbios_int_10h_09h(); break;
16135: case 0x0a: pcbios_int_10h_0ah(); break;
16136: case 0x0b: break;
1.1.1.40 root 16137: case 0x0c: pcbios_int_10h_0ch(); break;
16138: case 0x0d: pcbios_int_10h_0dh(); break;
1.1 root 16139: case 0x0e: pcbios_int_10h_0eh(); break;
16140: case 0x0f: pcbios_int_10h_0fh(); break;
16141: case 0x10: break;
1.1.1.14 root 16142: case 0x11: pcbios_int_10h_11h(); break;
16143: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 16144: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 16145: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 16146: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 16147: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
16148: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 16149: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 16150: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
16151: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 16152: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 16153: case 0x6f: break;
1.1.1.22 root 16154: case 0x80: m_CF = 1; break; // unknown
16155: case 0x81: m_CF = 1; break; // unknown
1.1 root 16156: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 16157: case 0x83: pcbios_int_10h_83h(); break;
16158: case 0x8b: break;
16159: case 0x8c: m_CF = 1; break; // unknown
16160: case 0x8d: m_CF = 1; break; // unknown
16161: case 0x8e: m_CF = 1; break; // unknown
16162: case 0x90: pcbios_int_10h_90h(); break;
16163: case 0x91: pcbios_int_10h_91h(); break;
16164: case 0x92: break;
16165: case 0x93: break;
16166: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 16167: case 0xfa: break; // ega register interface library is not installed
1.1 root 16168: case 0xfe: pcbios_int_10h_feh(); break;
16169: case 0xff: pcbios_int_10h_ffh(); break;
16170: default:
1.1.1.22 root 16171: 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));
16172: m_CF = 1;
1.1 root 16173: break;
16174: }
16175: break;
16176: case 0x11:
16177: // PC BIOS - Get Equipment List
1.1.1.26 root 16178: REG16(AX) = msdos_get_equipment();
1.1 root 16179: break;
16180: case 0x12:
16181: // PC BIOS - Get Memory Size
1.1.1.33 root 16182: REG16(AX) = *(UINT16 *)(mem + 0x413);
1.1 root 16183: break;
16184: case 0x13:
1.1.1.42 root 16185: // PC BIOS - Disk I/O
16186: {
16187: static UINT8 last = 0x00;
16188: switch(REG8(AH)) {
16189: case 0x00: pcbios_int_13h_00h(); break;
16190: case 0x01: // get last status
16191: REG8(AH) = last;
16192: break;
16193: case 0x02: pcbios_int_13h_02h(); break;
16194: case 0x03: pcbios_int_13h_03h(); break;
16195: case 0x04: pcbios_int_13h_04h(); break;
16196: case 0x08: pcbios_int_13h_08h(); break;
16197: case 0x0a: pcbios_int_13h_02h(); break;
16198: case 0x0b: pcbios_int_13h_03h(); break;
16199: case 0x0d: pcbios_int_13h_00h(); break;
16200: case 0x10: pcbios_int_13h_10h(); break;
16201: case 0x15: pcbios_int_13h_15h(); break;
1.1.1.43 root 16202: case 0x41: pcbios_int_13h_41h(); break;
1.1.1.42 root 16203: case 0x05: // format
16204: case 0x06:
16205: case 0x07:
16206: REG8(AH) = 0x0c; // unsupported track or invalid media
16207: m_CF = 1;
16208: break;
16209: case 0x09:
16210: case 0x0c: // seek
16211: case 0x11: // recalib
16212: case 0x14:
16213: case 0x17:
16214: REG8(AH) = 0x00; // successful completion
16215: break;
1.1.1.43 root 16216: case 0x21: // QUICKCACHE II v4.20 - Flush Cache
16217: case 0xa1: // Super PC-Kwik v3.20+ - Flush Cache
16218: REG8(AH) = 0x01; // invalid function
16219: m_CF = 1;
16220: break;
1.1.1.42 root 16221: default:
16222: unimplemented_13h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
16223: REG8(AH) = 0x01; // invalid function
16224: m_CF = 1;
16225: break;
16226: }
16227: last = REG8(AH);
16228: }
1.1 root 16229: break;
16230: case 0x14:
16231: // PC BIOS - Serial I/O
1.1.1.25 root 16232: switch(REG8(AH)) {
16233: case 0x00: pcbios_int_14h_00h(); break;
16234: case 0x01: pcbios_int_14h_01h(); break;
16235: case 0x02: pcbios_int_14h_02h(); break;
16236: case 0x03: pcbios_int_14h_03h(); break;
16237: case 0x04: pcbios_int_14h_04h(); break;
16238: case 0x05: pcbios_int_14h_05h(); break;
16239: default:
16240: 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));
16241: break;
16242: }
1.1 root 16243: break;
16244: case 0x15:
16245: // PC BIOS
1.1.1.3 root 16246: m_CF = 0;
1.1 root 16247: switch(REG8(AH)) {
1.1.1.14 root 16248: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 16249: case 0x23: pcbios_int_15h_23h(); break;
16250: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 16251: case 0x41: break;
1.1 root 16252: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 16253: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 16254: case 0x53: pcbios_int_15h_53h(); break;
1.1.1.43 root 16255: case 0x84: pcbios_int_15h_84h(); break;
1.1 root 16256: case 0x86: pcbios_int_15h_86h(); break;
16257: case 0x87: pcbios_int_15h_87h(); break;
16258: case 0x88: pcbios_int_15h_88h(); break;
16259: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 16260: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 16261: case 0xc0: // PS/2 ???
16262: case 0xc1:
16263: case 0xc2:
1.1.1.30 root 16264: case 0xc3: // PS50+ ???
16265: case 0xc4:
1.1.1.22 root 16266: REG8(AH) = 0x86;
16267: m_CF = 1;
16268: break;
1.1.1.3 root 16269: #if defined(HAS_I386)
1.1 root 16270: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 16271: #endif
1.1 root 16272: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 16273: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 16274: default:
1.1.1.22 root 16275: 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));
16276: REG8(AH) = 0x86;
1.1.1.3 root 16277: m_CF = 1;
1.1 root 16278: break;
16279: }
16280: break;
16281: case 0x16:
16282: // PC BIOS - Keyboard
1.1.1.3 root 16283: m_CF = 0;
1.1 root 16284: switch(REG8(AH)) {
16285: case 0x00: pcbios_int_16h_00h(); break;
16286: case 0x01: pcbios_int_16h_01h(); break;
16287: case 0x02: pcbios_int_16h_02h(); break;
16288: case 0x03: pcbios_int_16h_03h(); break;
16289: case 0x05: pcbios_int_16h_05h(); break;
16290: case 0x10: pcbios_int_16h_00h(); break;
16291: case 0x11: pcbios_int_16h_01h(); break;
16292: case 0x12: pcbios_int_16h_12h(); break;
16293: case 0x13: pcbios_int_16h_13h(); break;
16294: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 16295: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 16296: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 16297: case 0xda: break; // unknown
1.1.1.43 root 16298: case 0xdb: break; // unknown
1.1.1.22 root 16299: case 0xff: break; // unknown
1.1 root 16300: default:
1.1.1.22 root 16301: 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 16302: break;
16303: }
16304: break;
16305: case 0x17:
16306: // PC BIOS - Printer
1.1.1.37 root 16307: m_CF = 0;
16308: switch(REG8(AH)) {
16309: case 0x00: pcbios_int_17h_00h(); break;
16310: case 0x01: pcbios_int_17h_01h(); break;
16311: case 0x02: pcbios_int_17h_02h(); break;
16312: case 0x03: pcbios_int_17h_03h(); break;
16313: case 0x50: pcbios_int_17h_50h(); break;
16314: case 0x51: pcbios_int_17h_51h(); break;
16315: case 0x52: pcbios_int_17h_52h(); break;
16316: case 0x84: pcbios_int_17h_84h(); break;
16317: case 0x85: pcbios_int_17h_85h(); break;
16318: default:
16319: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
16320: break;
16321: }
1.1 root 16322: break;
16323: case 0x1a:
16324: // PC BIOS - Timer
1.1.1.3 root 16325: m_CF = 0;
1.1 root 16326: switch(REG8(AH)) {
16327: case 0x00: pcbios_int_1ah_00h(); break;
16328: case 0x01: break;
16329: case 0x02: pcbios_int_1ah_02h(); break;
16330: case 0x03: break;
16331: case 0x04: pcbios_int_1ah_04h(); break;
16332: case 0x05: break;
16333: case 0x0a: pcbios_int_1ah_0ah(); break;
16334: case 0x0b: break;
1.1.1.14 root 16335: case 0x35: break; // Word Perfect Third Party Interface?
16336: case 0x36: break; // Word Perfect Third Party Interface
16337: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1.1.44 root 16338: case 0xb0: break; // Microsoft Real-Time Compression Interface (MRCI)
1.1.1.43 root 16339: case 0xb1: break; // PCI BIOS v2.0c+
16340: case 0xb4: break; // Intel Plug-and-Play Auto-Configuration
1.1 root 16341: default:
1.1.1.22 root 16342: 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 16343: break;
16344: }
16345: break;
1.1.1.33 root 16346: case 0x1b:
16347: mem[0x471] = 0x00;
16348: break;
1.1 root 16349: case 0x20:
1.1.1.28 root 16350: try {
16351: msdos_process_terminate(SREG(CS), retval, 1);
16352: } catch(...) {
16353: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
16354: }
1.1 root 16355: break;
1.1.1.49! root 16356: case 0x30:
1.1.1.46 root 16357: // dummy interrupt for case map routine pointed in the country info
16358: // if(!(REG8(CL) >= 0x00 && REG8(CL) <= 0x24)) {
16359: // REG8(AL) = 0x00;
16360: // break;
16361: // }
1.1 root 16362: case 0x21:
16363: // MS-DOS System Call
1.1.1.3 root 16364: m_CF = 0;
1.1.1.28 root 16365: try {
1.1.1.46 root 16366: switch(num == 0x21 ? REG8(AH) : REG8(CL)) {
1.1.1.28 root 16367: case 0x00: msdos_int_21h_00h(); break;
16368: case 0x01: msdos_int_21h_01h(); break;
16369: case 0x02: msdos_int_21h_02h(); break;
16370: case 0x03: msdos_int_21h_03h(); break;
16371: case 0x04: msdos_int_21h_04h(); break;
16372: case 0x05: msdos_int_21h_05h(); break;
16373: case 0x06: msdos_int_21h_06h(); break;
16374: case 0x07: msdos_int_21h_07h(); break;
16375: case 0x08: msdos_int_21h_08h(); break;
16376: case 0x09: msdos_int_21h_09h(); break;
16377: case 0x0a: msdos_int_21h_0ah(); break;
16378: case 0x0b: msdos_int_21h_0bh(); break;
16379: case 0x0c: msdos_int_21h_0ch(); break;
16380: case 0x0d: msdos_int_21h_0dh(); break;
16381: case 0x0e: msdos_int_21h_0eh(); break;
16382: case 0x0f: msdos_int_21h_0fh(); break;
16383: case 0x10: msdos_int_21h_10h(); break;
16384: case 0x11: msdos_int_21h_11h(); break;
16385: case 0x12: msdos_int_21h_12h(); break;
16386: case 0x13: msdos_int_21h_13h(); break;
16387: case 0x14: msdos_int_21h_14h(); break;
16388: case 0x15: msdos_int_21h_15h(); break;
16389: case 0x16: msdos_int_21h_16h(); break;
16390: case 0x17: msdos_int_21h_17h(); break;
16391: case 0x18: msdos_int_21h_18h(); break;
16392: case 0x19: msdos_int_21h_19h(); break;
16393: case 0x1a: msdos_int_21h_1ah(); break;
16394: case 0x1b: msdos_int_21h_1bh(); break;
16395: case 0x1c: msdos_int_21h_1ch(); break;
16396: case 0x1d: msdos_int_21h_1dh(); break;
16397: case 0x1e: msdos_int_21h_1eh(); break;
16398: case 0x1f: msdos_int_21h_1fh(); break;
16399: case 0x20: msdos_int_21h_20h(); break;
16400: case 0x21: msdos_int_21h_21h(); break;
16401: case 0x22: msdos_int_21h_22h(); break;
16402: case 0x23: msdos_int_21h_23h(); break;
16403: case 0x24: msdos_int_21h_24h(); break;
16404: case 0x25: msdos_int_21h_25h(); break;
16405: case 0x26: msdos_int_21h_26h(); break;
16406: case 0x27: msdos_int_21h_27h(); break;
16407: case 0x28: msdos_int_21h_28h(); break;
16408: case 0x29: msdos_int_21h_29h(); break;
16409: case 0x2a: msdos_int_21h_2ah(); break;
16410: case 0x2b: msdos_int_21h_2bh(); break;
16411: case 0x2c: msdos_int_21h_2ch(); break;
16412: case 0x2d: msdos_int_21h_2dh(); break;
16413: case 0x2e: msdos_int_21h_2eh(); break;
16414: case 0x2f: msdos_int_21h_2fh(); break;
16415: case 0x30: msdos_int_21h_30h(); break;
16416: case 0x31: msdos_int_21h_31h(); break;
16417: case 0x32: msdos_int_21h_32h(); break;
16418: case 0x33: msdos_int_21h_33h(); break;
16419: case 0x34: msdos_int_21h_34h(); break;
16420: case 0x35: msdos_int_21h_35h(); break;
16421: case 0x36: msdos_int_21h_36h(); break;
16422: case 0x37: msdos_int_21h_37h(); break;
16423: case 0x38: msdos_int_21h_38h(); break;
16424: case 0x39: msdos_int_21h_39h(0); break;
16425: case 0x3a: msdos_int_21h_3ah(0); break;
16426: case 0x3b: msdos_int_21h_3bh(0); break;
16427: case 0x3c: msdos_int_21h_3ch(); break;
16428: case 0x3d: msdos_int_21h_3dh(); break;
16429: case 0x3e: msdos_int_21h_3eh(); break;
16430: case 0x3f: msdos_int_21h_3fh(); break;
16431: case 0x40: msdos_int_21h_40h(); break;
16432: case 0x41: msdos_int_21h_41h(0); break;
16433: case 0x42: msdos_int_21h_42h(); break;
16434: case 0x43: msdos_int_21h_43h(0); break;
16435: case 0x44: msdos_int_21h_44h(); break;
16436: case 0x45: msdos_int_21h_45h(); break;
16437: case 0x46: msdos_int_21h_46h(); break;
16438: case 0x47: msdos_int_21h_47h(0); break;
16439: case 0x48: msdos_int_21h_48h(); break;
16440: case 0x49: msdos_int_21h_49h(); break;
16441: case 0x4a: msdos_int_21h_4ah(); break;
16442: case 0x4b: msdos_int_21h_4bh(); break;
16443: case 0x4c: msdos_int_21h_4ch(); break;
16444: case 0x4d: msdos_int_21h_4dh(); break;
16445: case 0x4e: msdos_int_21h_4eh(); break;
16446: case 0x4f: msdos_int_21h_4fh(); break;
16447: case 0x50: msdos_int_21h_50h(); break;
16448: case 0x51: msdos_int_21h_51h(); break;
16449: case 0x52: msdos_int_21h_52h(); break;
1.1.1.43 root 16450: case 0x53: msdos_int_21h_53h(); break;
1.1.1.28 root 16451: case 0x54: msdos_int_21h_54h(); break;
16452: case 0x55: msdos_int_21h_55h(); break;
16453: case 0x56: msdos_int_21h_56h(0); break;
16454: case 0x57: msdos_int_21h_57h(); break;
16455: case 0x58: msdos_int_21h_58h(); break;
16456: case 0x59: msdos_int_21h_59h(); break;
16457: case 0x5a: msdos_int_21h_5ah(); break;
16458: case 0x5b: msdos_int_21h_5bh(); break;
16459: case 0x5c: msdos_int_21h_5ch(); break;
16460: case 0x5d: msdos_int_21h_5dh(); break;
1.1.1.42 root 16461: case 0x5e: msdos_int_21h_5eh(); break;
1.1.1.30 root 16462: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 16463: case 0x60: msdos_int_21h_60h(0); break;
16464: case 0x61: msdos_int_21h_61h(); break;
16465: case 0x62: msdos_int_21h_62h(); break;
16466: case 0x63: msdos_int_21h_63h(); break;
1.1.1.33 root 16467: // 0x64: Set Device Driver Lockahead Flag
1.1.1.28 root 16468: case 0x65: msdos_int_21h_65h(); break;
16469: case 0x66: msdos_int_21h_66h(); break;
16470: case 0x67: msdos_int_21h_67h(); break;
16471: case 0x68: msdos_int_21h_68h(); break;
16472: case 0x69: msdos_int_21h_69h(); break;
16473: case 0x6a: msdos_int_21h_6ah(); break;
16474: case 0x6b: msdos_int_21h_6bh(); break;
16475: case 0x6c: msdos_int_21h_6ch(0); break;
1.1.1.48 root 16476: case 0x6d: // Find First ROM Program
16477: case 0x6e: // Find Next ROM Program
16478: case 0x6f: // Get/Set ROM Scan Start Address
16479: REG8(AL) = 0x00; // if not supported (DOS <5, MS-DOS 5+ non-ROM versions)
16480: break;
1.1.1.43 root 16481: case 0x70: msdos_int_21h_70h(); break;
1.1.1.48 root 16482: case 0x71: // Windows95 - Long Filename Functions
1.1.1.28 root 16483: switch(REG8(AL)) {
16484: case 0x0d: msdos_int_21h_710dh(); break;
16485: case 0x39: msdos_int_21h_39h(1); break;
16486: case 0x3a: msdos_int_21h_3ah(1); break;
16487: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.48 root 16488: case 0x41: msdos_int_21h_7141h(); break;
1.1.1.28 root 16489: case 0x43: msdos_int_21h_43h(1); break;
16490: case 0x47: msdos_int_21h_47h(1); break;
16491: case 0x4e: msdos_int_21h_714eh(); break;
16492: case 0x4f: msdos_int_21h_714fh(); break;
16493: case 0x56: msdos_int_21h_56h(1); break;
16494: case 0x60: msdos_int_21h_60h(1); break;
16495: case 0x6c: msdos_int_21h_6ch(1); break;
16496: case 0xa0: msdos_int_21h_71a0h(); break;
16497: case 0xa1: msdos_int_21h_71a1h(); break;
16498: case 0xa6: msdos_int_21h_71a6h(); break;
16499: case 0xa7: msdos_int_21h_71a7h(); break;
16500: case 0xa8: msdos_int_21h_71a8h(); break;
1.1.1.45 root 16501: case 0xa9: msdos_int_21h_6ch(1); break;
1.1.1.28 root 16502: case 0xaa: msdos_int_21h_71aah(); break;
16503: default:
16504: 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));
16505: REG16(AX) = 0x7100;
16506: m_CF = 1;
16507: break;
16508: }
16509: break;
1.1.1.48 root 16510: case 0x72: // Windows95 beta - LFN FindClose
16511: // 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));
16512: REG16(AX) = 0x7200;
16513: m_CF = 1;
16514: break;
16515: case 0x73: // Windows95 - FAT32 Functions
1.1.1.28 root 16516: switch(REG8(AL)) {
16517: case 0x00: msdos_int_21h_7300h(); break;
1.1.1.33 root 16518: // 0x01: Set Drive Locking ???
1.1.1.28 root 16519: case 0x02: msdos_int_21h_7302h(); break;
16520: case 0x03: msdos_int_21h_7303h(); break;
1.1.1.33 root 16521: // 0x04: Set DPB to Use for Formatting
16522: // 0x05: Extended Absolute Disk Read/Write
1.1.1.28 root 16523: default:
16524: 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));
16525: REG16(AX) = 0x7300;
16526: m_CF = 1;
16527: break;
16528: }
1.1 root 16529: break;
1.1.1.30 root 16530: case 0xdb: msdos_int_21h_dbh(); break;
16531: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 16532: default:
1.1.1.22 root 16533: 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 16534: REG16(AX) = 0x01;
1.1.1.3 root 16535: m_CF = 1;
1.1 root 16536: break;
16537: }
1.1.1.28 root 16538: } catch(int error) {
16539: REG16(AX) = error;
16540: m_CF = 1;
16541: } catch(...) {
16542: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 16543: m_CF = 1;
1.1 root 16544: }
1.1.1.3 root 16545: if(m_CF) {
1.1.1.23 root 16546: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1.1.1.47 root 16547: sda->int21h_5d0ah_called = 0;
1.1.1.23 root 16548: sda->extended_error_code = REG16(AX);
16549: switch(sda->extended_error_code) {
16550: case 4: // Too many open files
16551: case 8: // Insufficient memory
16552: sda->error_class = 1; // Out of resource
16553: break;
16554: case 5: // Access denied
16555: sda->error_class = 3; // Authorization
16556: break;
16557: case 7: // Memory control block destroyed
16558: sda->error_class = 4; // Internal
16559: break;
16560: case 2: // File not found
16561: case 3: // Path not found
16562: case 15: // Invaid drive specified
16563: case 18: // No more files
16564: sda->error_class = 8; // Not found
16565: break;
16566: case 32: // Sharing violation
16567: case 33: // Lock violation
16568: sda->error_class = 10; // Locked
16569: break;
16570: // case 16: // Removal of current directory attempted
16571: case 19: // Attempted write on protected disk
16572: case 21: // Drive not ready
16573: // case 29: // Write failure
16574: // case 30: // Read failure
16575: // case 82: // Cannot create subdirectory
16576: sda->error_class = 11; // Media
16577: break;
16578: case 80: // File already exists
16579: sda->error_class = 12; // Already exist
16580: break;
16581: default:
16582: sda->error_class = 13; // Unknown
16583: break;
16584: }
16585: sda->suggested_action = 1; // Retry
16586: sda->locus_of_last_error = 1; // Unknown
1.1 root 16587: }
1.1.1.33 root 16588: if(ctrl_break_checking && ctrl_break_detected) {
1.1.1.26 root 16589: // raise int 23h
16590: #if defined(HAS_I386)
16591: m_ext = 0; // not an external interrupt
16592: i386_trap(0x23, 1, 0);
16593: m_ext = 1;
16594: #else
16595: PREFIX86(_interrupt)(0x23);
16596: #endif
16597: }
1.1 root 16598: break;
16599: case 0x22:
16600: fatalerror("int 22h (terminate address)\n");
16601: case 0x23:
1.1.1.28 root 16602: try {
16603: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
16604: } catch(...) {
16605: fatalerror("failed to terminate the current process by int 23h\n");
16606: }
1.1 root 16607: break;
16608: case 0x24:
1.1.1.32 root 16609: /*
1.1.1.28 root 16610: try {
16611: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
16612: } catch(...) {
16613: fatalerror("failed to terminate the current process by int 24h\n");
16614: }
1.1.1.32 root 16615: */
16616: msdos_int_24h();
1.1 root 16617: break;
16618: case 0x25:
16619: msdos_int_25h();
16620: break;
16621: case 0x26:
16622: msdos_int_26h();
16623: break;
16624: case 0x27:
1.1.1.28 root 16625: try {
16626: msdos_int_27h();
16627: } catch(...) {
16628: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
16629: }
1.1 root 16630: break;
16631: case 0x28:
16632: Sleep(10);
1.1.1.35 root 16633: REQUEST_HARDWRE_UPDATE();
1.1 root 16634: break;
16635: case 0x29:
16636: msdos_int_29h();
16637: break;
16638: case 0x2e:
16639: msdos_int_2eh();
16640: break;
16641: case 0x2f:
16642: // multiplex interrupt
16643: switch(REG8(AH)) {
1.1.1.22 root 16644: case 0x05: msdos_int_2fh_05h(); break;
1.1.1.44 root 16645: case 0x06: msdos_int_2fh_06h(); break;
1.1.1.22 root 16646: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 16647: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 16648: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 16649: case 0x14: msdos_int_2fh_14h(); break;
16650: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 16651: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 16652: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 16653: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 16654: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 16655: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 16656: case 0x46: msdos_int_2fh_46h(); break;
16657: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 16658: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 16659: case 0x4b: msdos_int_2fh_4bh(); break;
1.1.1.44 root 16660: case 0x4d: msdos_int_2fh_4dh(); break;
1.1 root 16661: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 16662: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.44 root 16663: case 0x56: msdos_int_2fh_56h(); break;
1.1.1.24 root 16664: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 16665: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.34 root 16666: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.43 root 16667: default:
1.1.1.30 root 16668: switch(REG8(AL)) {
16669: case 0x00:
16670: // This is not installed
16671: // REG8(AL) = 0x00;
16672: break;
1.1.1.33 root 16673: case 0x01:
1.1.1.42 root 16674: // Quarterdeck RPCI - QEMM/QRAM - PCL-838.EXE is not installed
16675: if(REG8(AH) == 0xd2 && REG16(BX) == 0x5145 && REG16(CX) == 0x4d4d && REG16(DX) == 0x3432) {
16676: break;
16677: }
1.1.1.33 root 16678: // Banyan VINES v4+ is not installed
16679: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
16680: break;
16681: }
1.1.1.42 root 16682: // Quarterdeck QDPMI.SYS v1.0 is not installed
16683: if(REG8(AH) == 0xde && REG16(BX) == 0x4450 && REG16(CX) == 0x4d49 && REG16(DX) == 0x8f4f) {
16684: break;
16685: }
1.1.1.30 root 16686: default:
1.1.1.42 root 16687: // NORTON UTILITIES 5.0+
16688: if(REG8(AH) == 0xfe && REG16(DI) == 0x4e55) {
16689: break;
16690: }
1.1.1.30 root 16691: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.43 root 16692: REG16(AX) = 0x01; // invalid function
1.1.1.30 root 16693: m_CF = 1;
16694: break;
16695: }
16696: break;
1.1 root 16697: }
16698: break;
1.1.1.24 root 16699: case 0x33:
16700: switch(REG8(AH)) {
16701: case 0x00:
16702: // Mouse
1.1.1.49! root 16703: switch(REG16(AX)) {
! 16704: case 0x0000: msdos_int_33h_0000h(); break;
! 16705: case 0x0001: msdos_int_33h_0001h(); break;
! 16706: case 0x0002: msdos_int_33h_0002h(); break;
! 16707: case 0x0003: msdos_int_33h_0003h(); break;
! 16708: case 0x0004: msdos_int_33h_0004h(); break;
! 16709: case 0x0005: msdos_int_33h_0005h(); break;
! 16710: case 0x0006: msdos_int_33h_0006h(); break;
! 16711: case 0x0007: msdos_int_33h_0007h(); break;
! 16712: case 0x0008: msdos_int_33h_0008h(); break;
! 16713: case 0x0009: msdos_int_33h_0009h(); break;
! 16714: case 0x000a: msdos_int_33h_000ah(); break;
! 16715: case 0x000b: msdos_int_33h_000bh(); break;
! 16716: case 0x000c: msdos_int_33h_000ch(); break;
! 16717: case 0x000d: break; // MS MOUSE v1.0+ - Light Pen Emulation On
! 16718: case 0x000e: break; // MS MOUSE v1.0+ - Light Pen Emulation Off
! 16719: case 0x000f: msdos_int_33h_000fh(); break;
! 16720: case 0x0010: break; // MS MOUSE v1.0+ - Define Screen Region for Updating
! 16721: case 0x0011: msdos_int_33h_0011h(); break;
! 16722: case 0x0012: REG16(AX) = 0xffff; break; // MS MOUSE - Set Large Graphics Cursor Block
! 16723: case 0x0013: break; // MS MOUSE v5.0+ - Define Double-Speed Threshold
! 16724: case 0x0014: msdos_int_33h_0014h(); break;
! 16725: case 0x0015: msdos_int_33h_0015h(); break;
! 16726: case 0x0016: msdos_int_33h_0016h(); break;
! 16727: case 0x0017: msdos_int_33h_0017h(); break;
! 16728: case 0x0018: msdos_int_33h_0018h(); break;
! 16729: case 0x0019: msdos_int_33h_0019h(); break;
! 16730: case 0x001a: msdos_int_33h_001ah(); break;
! 16731: case 0x001b: msdos_int_33h_001bh(); break;
! 16732: case 0x001c: break; // MS MOUSE v6.0+ - Set Interrupt Rate
! 16733: case 0x001d: msdos_int_33h_001dh(); break;
! 16734: case 0x001e: msdos_int_33h_001eh(); break;
! 16735: case 0x001f: msdos_int_33h_001fh(); break;
! 16736: case 0x0020: msdos_int_33h_0020h(); break;
! 16737: case 0x0021: msdos_int_33h_0021h(); break;
! 16738: case 0x0022: msdos_int_33h_0022h(); break;
! 16739: case 0x0023: msdos_int_33h_0023h(); break;
! 16740: case 0x0024: msdos_int_33h_0024h(); break;
! 16741: case 0x0025: msdos_int_33h_0025h(); break;
! 16742: case 0x0026: msdos_int_33h_0026h(); break;
! 16743: case 0x0027: msdos_int_33h_0027h(); break;
! 16744: case 0x0028: msdos_int_33h_0028h(); break;
! 16745: case 0x0029: msdos_int_33h_0029h(); break;
! 16746: case 0x002a: msdos_int_33h_002ah(); break;
! 16747: // 0x002b: MS MOUSE v7.0+ - Load Acceleration Profiles
! 16748: // 0x002c: MS MOUSE v7.0+ - Get Acceleration Profiles
! 16749: // 0x002d: MS MOUSE v7.0+ - Select Acceleration Profile
! 16750: // 0x002e: MS MOUSE v8.10+ - Set Acceleration Profile Names
! 16751: case 0x002f: break; // Mouse Hardware Reset
! 16752: // 0x0030: MS MOUSE v7.04+ - Get/Set BallPoint Information
! 16753: case 0x0031: msdos_int_33h_0031h(); break;
! 16754: case 0x0032: msdos_int_33h_0032h(); break;
! 16755: // 0x0033: MS MOUSE v7.05+ - Get Switch Settings And Acceleration Profile Data
! 16756: // 0x0034: MS MOUSE v8.0+ - Get Initialization File
! 16757: // 0x0035: MS MOUSE v8.10+ - LCD Screen Large Pointer Support
! 16758: case 0x004d: msdos_int_33h_004dh(); break;
! 16759: case 0x006d: msdos_int_33h_006dh(); break;
1.1.1.24 root 16760: default:
16761: 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));
16762: break;
16763: }
16764: break;
16765: default:
16766: 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));
16767: break;
16768: }
16769: break;
1.1.1.19 root 16770: case 0x68:
16771: // dummy interrupt for EMS (int 67h)
16772: switch(REG8(AH)) {
16773: case 0x40: msdos_int_67h_40h(); break;
16774: case 0x41: msdos_int_67h_41h(); break;
16775: case 0x42: msdos_int_67h_42h(); break;
16776: case 0x43: msdos_int_67h_43h(); break;
16777: case 0x44: msdos_int_67h_44h(); break;
16778: case 0x45: msdos_int_67h_45h(); break;
16779: case 0x46: msdos_int_67h_46h(); break;
16780: case 0x47: msdos_int_67h_47h(); break;
16781: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 16782: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
16783: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 16784: case 0x4b: msdos_int_67h_4bh(); break;
16785: case 0x4c: msdos_int_67h_4ch(); break;
16786: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 16787: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 16788: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 16789: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 16790: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 16791: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 16792: case 0x53: msdos_int_67h_53h(); break;
16793: case 0x54: msdos_int_67h_54h(); break;
1.1.1.49! root 16794: case 0x55: msdos_int_67h_55h(); break;
! 16795: case 0x56: msdos_int_67h_56h(); break;
1.1.1.20 root 16796: case 0x57: msdos_int_67h_57h(); break;
16797: case 0x58: msdos_int_67h_58h(); break;
1.1.1.42 root 16798: case 0x59: msdos_int_67h_59h(); break;
1.1.1.20 root 16799: case 0x5a: msdos_int_67h_5ah(); break;
1.1.1.49! root 16800: case 0x5b: msdos_int_67h_5bh(); break;
1.1.1.43 root 16801: // 0x5c: LIM EMS 4.0 - Prepare Expanded Memory Hardware For Warm Boot
16802: case 0x5d: msdos_int_67h_5dh(); break;
1.1.1.49! root 16803: case 0x70: msdos_int_67h_70h(); break;
1.1.1.31 root 16804: // 0xde: VCPI
1.1.1.30 root 16805: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 16806: default:
1.1.1.22 root 16807: 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 16808: REG8(AH) = 0x84;
16809: break;
16810: }
16811: break;
16812: #ifdef SUPPORT_XMS
16813: case 0x69:
16814: // dummy interrupt for XMS (call far)
1.1.1.28 root 16815: try {
16816: switch(REG8(AH)) {
16817: case 0x00: msdos_call_xms_00h(); break;
16818: case 0x01: msdos_call_xms_01h(); break;
16819: case 0x02: msdos_call_xms_02h(); break;
16820: case 0x03: msdos_call_xms_03h(); break;
16821: case 0x04: msdos_call_xms_04h(); break;
16822: case 0x05: msdos_call_xms_05h(); break;
16823: case 0x06: msdos_call_xms_06h(); break;
16824: case 0x07: msdos_call_xms_07h(); break;
16825: case 0x08: msdos_call_xms_08h(); break;
16826: case 0x09: msdos_call_xms_09h(); break;
16827: case 0x0a: msdos_call_xms_0ah(); break;
16828: case 0x0b: msdos_call_xms_0bh(); break;
16829: case 0x0c: msdos_call_xms_0ch(); break;
16830: case 0x0d: msdos_call_xms_0dh(); break;
16831: case 0x0e: msdos_call_xms_0eh(); break;
16832: case 0x0f: msdos_call_xms_0fh(); break;
16833: case 0x10: msdos_call_xms_10h(); break;
16834: case 0x11: msdos_call_xms_11h(); break;
16835: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 16836: #if defined(HAS_I386)
16837: case 0x88: msdos_call_xms_88h(); break;
16838: case 0x89: msdos_call_xms_89h(); break;
16839: case 0x8e: msdos_call_xms_8eh(); break;
16840: case 0x8f: msdos_call_xms_8fh(); break;
16841: #endif
1.1.1.28 root 16842: default:
16843: 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));
16844: REG16(AX) = 0x0000;
16845: REG8(BL) = 0x80; // function not implemented
16846: break;
16847: }
16848: } catch(...) {
1.1.1.19 root 16849: REG16(AX) = 0x0000;
1.1.1.28 root 16850: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 16851: }
16852: break;
16853: #endif
16854: case 0x6a:
1.1.1.24 root 16855: // irq12 (mouse)
16856: mouse_push_ax = REG16(AX);
16857: mouse_push_bx = REG16(BX);
16858: mouse_push_cx = REG16(CX);
16859: mouse_push_dx = REG16(DX);
16860: mouse_push_si = REG16(SI);
16861: mouse_push_di = REG16(DI);
16862:
1.1.1.43 root 16863: if(mouse.status_irq && mouse.call_addr.dw) {
1.1.1.24 root 16864: REG16(AX) = mouse.status_irq;
16865: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 16866: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
16867: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
1.1.1.24 root 16868: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
16869: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
16870:
1.1.1.49! root 16871: mem[DUMMY_TOP + 0x02] = 0x9a; // call far
! 16872: mem[DUMMY_TOP + 0x03] = mouse.call_addr.w.l & 0xff;
! 16873: mem[DUMMY_TOP + 0x04] = mouse.call_addr.w.l >> 8;
! 16874: mem[DUMMY_TOP + 0x05] = mouse.call_addr.w.h & 0xff;
! 16875: mem[DUMMY_TOP + 0x06] = mouse.call_addr.w.h >> 8;
1.1.1.43 root 16876: break;
1.1.1.24 root 16877: }
1.1.1.43 root 16878: for(int i = 0; i < 8; i++) {
16879: if((mouse.status_irq_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
16880: REG16(AX) = mouse.status_irq_alt;
16881: REG16(BX) = mouse.get_buttons();
16882: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
16883: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
16884: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
16885: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
16886:
1.1.1.49! root 16887: mem[DUMMY_TOP + 0x02] = 0x9a; // call far
! 16888: mem[DUMMY_TOP + 0x03] = mouse.call_addr_alt[i].w.l & 0xff;
! 16889: mem[DUMMY_TOP + 0x04] = mouse.call_addr_alt[i].w.l >> 8;
! 16890: mem[DUMMY_TOP + 0x05] = mouse.call_addr_alt[i].w.h & 0xff;
! 16891: mem[DUMMY_TOP + 0x06] = mouse.call_addr_alt[i].w.h >> 8;
1.1.1.43 root 16892: break;
16893: }
16894: }
16895: // invalid call addr :-(
1.1.1.49! root 16896: mem[DUMMY_TOP + 0x02] = 0x90; // nop
! 16897: mem[DUMMY_TOP + 0x03] = 0x90; // nop
! 16898: mem[DUMMY_TOP + 0x04] = 0x90; // nop
! 16899: mem[DUMMY_TOP + 0x05] = 0x90; // nop
! 16900: mem[DUMMY_TOP + 0x06] = 0x90; // nop
1.1.1.24 root 16901: break;
16902: case 0x6b:
16903: // end of irq12 (mouse)
16904: REG16(AX) = mouse_push_ax;
16905: REG16(BX) = mouse_push_bx;
16906: REG16(CX) = mouse_push_cx;
16907: REG16(DX) = mouse_push_dx;
16908: REG16(SI) = mouse_push_si;
16909: REG16(DI) = mouse_push_di;
16910:
16911: // EOI
16912: if((pic[1].isr &= ~(1 << 4)) == 0) {
16913: pic[0].isr &= ~(1 << 2); // master
16914: }
16915: pic_update();
16916: break;
16917: case 0x6c:
1.1.1.19 root 16918: // dummy interrupt for case map routine pointed in the country info
16919: if(REG8(AL) >= 0x80) {
16920: char tmp[2] = {0};
16921: tmp[0] = REG8(AL);
16922: my_strupr(tmp);
16923: REG8(AL) = tmp[0];
16924: }
16925: break;
1.1.1.27 root 16926: case 0x6d:
16927: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
16928: REG8(AL) = 0x86; // not supported
16929: m_CF = 1;
16930: break;
1.1.1.32 root 16931: case 0x6e:
16932: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
16933: {
16934: UINT16 code = REG16(AX);
16935: if(code & 0xf0) {
16936: code = (code & 7) | ((code & 0x10) >> 1);
16937: }
16938: for(int i = 0; i < array_length(param_error_table); i++) {
16939: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
16940: const char *message = NULL;
16941: if(active_code_page == 932) {
16942: message = param_error_table[i].message_japanese;
16943: }
16944: if(message == NULL) {
16945: message = param_error_table[i].message_english;
16946: }
16947: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
16948: strcpy((char *)(mem + WORK_TOP + 1), message);
16949:
16950: SREG(ES) = WORK_TOP >> 4;
16951: i386_load_segment_descriptor(ES);
16952: REG16(DI) = 0x0000;
16953: break;
16954: }
16955: }
16956: }
16957: break;
1.1.1.49! root 16958: case 0x6f:
! 16959: // dummy interrupt for end of alter page map and call
! 16960: {
! 16961: UINT16 handles[4], pages[4];
! 16962:
! 16963: // pop old mapping data in new mapping
! 16964: for(int i = 0; i < 4; i++) {
! 16965: pages [3 - i] = i386_pop16();
! 16966: handles[3 - i] = i386_pop16();
! 16967: }
! 16968:
! 16969: // restore old mapping
! 16970: for(int i = 0; i < 4; i++) {
! 16971: UINT16 handle = handles[i];
! 16972: UINT16 page = pages [i];
! 16973:
! 16974: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
! 16975: ems_map_page(i, handle, page);
! 16976: } else {
! 16977: ems_unmap_page(i);
! 16978: }
! 16979: }
! 16980: // do ret_far (pop cs/ip) in old mapping
! 16981: }
! 16982: break;
1.1.1.8 root 16983: case 0x70:
16984: case 0x71:
16985: case 0x72:
16986: case 0x73:
16987: case 0x74:
16988: case 0x75:
16989: case 0x76:
16990: case 0x77:
16991: // EOI
16992: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
16993: pic[0].isr &= ~(1 << 2); // master
16994: }
16995: pic_update();
16996: break;
1.1 root 16997: default:
1.1.1.22 root 16998: // 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 16999: break;
17000: }
17001:
17002: // update cursor position
17003: if(cursor_moved) {
1.1.1.36 root 17004: pcbios_update_cursor_position();
1.1 root 17005: cursor_moved = false;
17006: }
17007: }
17008:
17009: // init
17010:
17011: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
17012: {
17013: // init file handler
17014: memset(file_handler, 0, sizeof(file_handler));
17015: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
17016: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
17017: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 17018: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 17019: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 17020: #else
17021: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
17022: #endif
17023: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 17024: }
1.1.1.21 root 17025: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.45 root 17026: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
17027: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1
1.1.1.21 root 17028: }
1.1 root 17029: _dup2(0, DUP_STDIN);
17030: _dup2(1, DUP_STDOUT);
17031: _dup2(2, DUP_STDERR);
1.1.1.21 root 17032: _dup2(3, DUP_STDAUX);
17033: _dup2(4, DUP_STDPRN);
1.1 root 17034:
1.1.1.24 root 17035: // init mouse
17036: memset(&mouse, 0, sizeof(mouse));
1.1.1.34 root 17037: mouse.enabled = true; // from DOSBox
17038: mouse.hidden = 1; // hidden in default ???
17039: mouse.old_hidden = 1; // from DOSBox
17040: mouse.max_position.x = 8 * (scr_width - 1);
17041: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 17042: mouse.mickey.x = 8;
17043: mouse.mickey.y = 16;
17044:
1.1.1.26 root 17045: #ifdef SUPPORT_XMS
17046: // init xms
17047: msdos_xms_init();
17048: #endif
17049:
1.1 root 17050: // init process
17051: memset(process, 0, sizeof(process));
17052:
1.1.1.13 root 17053: // init dtainfo
17054: msdos_dta_info_init();
17055:
1.1 root 17056: // init memory
17057: memset(mem, 0, sizeof(mem));
17058:
17059: // bios data area
1.1.1.23 root 17060: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 17061: CONSOLE_SCREEN_BUFFER_INFO csbi;
17062: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 17063: CONSOLE_FONT_INFO cfi;
17064: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
17065:
17066: int regen = min(scr_width * scr_height * 2, 0x8000);
17067: text_vram_top_address = TEXT_VRAM_TOP;
17068: text_vram_end_address = text_vram_top_address + regen;
17069: shadow_buffer_top_address = SHADOW_BUF_TOP;
17070: shadow_buffer_end_address = shadow_buffer_top_address + regen;
17071:
17072: if(regen > 0x4000) {
17073: regen = 0x8000;
17074: vram_pages = 1;
17075: } else if(regen > 0x2000) {
17076: regen = 0x4000;
17077: vram_pages = 2;
17078: } else if(regen > 0x1000) {
17079: regen = 0x2000;
17080: vram_pages = 4;
17081: } else {
17082: regen = 0x1000;
17083: vram_pages = 8;
17084: }
1.1 root 17085:
1.1.1.25 root 17086: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
17087: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 17088: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
17089: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 17090: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.37 root 17091: *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
17092: *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32 root 17093: #ifdef EXT_BIOS_TOP
1.1.1.25 root 17094: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32 root 17095: #endif
1.1.1.26 root 17096: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1.1.33 root 17097: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
1.1.1.41 root 17098: *(UINT16 *)(mem + 0x41a) = 0x1e;
17099: *(UINT16 *)(mem + 0x41c) = 0x1e;
1.1 root 17100: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 17101: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
17102: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 17103: *(UINT16 *)(mem + 0x44e) = 0;
17104: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 17105: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 17106: *(UINT8 *)(mem + 0x460) = 7;
17107: *(UINT8 *)(mem + 0x461) = 7;
17108: *(UINT8 *)(mem + 0x462) = 0;
17109: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 17110: *(UINT8 *)(mem + 0x465) = 0x09;
17111: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.40 root 17112: *(UINT16 *)(mem + 0x472) = 0x4321; // preserve memory in cpu reset
1.1.1.41 root 17113: *(UINT16 *)(mem + 0x480) = 0x1e;
17114: *(UINT16 *)(mem + 0x482) = 0x3e;
1.1.1.14 root 17115: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
17116: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
17117: *(UINT8 *)(mem + 0x487) = 0x60;
17118: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32 root 17119: #ifdef EXT_BIOS_TOP
1.1.1.25 root 17120: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32 root 17121: #endif
1.1.1.14 root 17122:
17123: // initial screen
17124: SMALL_RECT rect;
17125: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
17126: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
17127: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
17128: for(int x = 0; x < scr_width; x++) {
17129: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
17130: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
17131: }
17132: }
1.1 root 17133:
1.1.1.19 root 17134: // init mcb
1.1 root 17135: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 17136:
17137: // iret table
17138: // note: int 2eh vector should address the routine in command.com,
17139: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
17140: // so move iret table into allocated memory block
17141: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
1.1.1.33 root 17142: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, IRET_SIZE >> 4);
1.1.1.19 root 17143: IRET_TOP = seg << 4;
17144: seg += IRET_SIZE >> 4;
1.1.1.25 root 17145: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 17146:
17147: // dummy xms/ems device
1.1.1.33 root 17148: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
1.1.1.19 root 17149: XMS_TOP = seg << 4;
17150: seg += XMS_SIZE >> 4;
17151:
17152: // environment
1.1.1.33 root 17153: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
1.1 root 17154: int env_seg = seg;
17155: int ofs = 0;
1.1.1.32 root 17156: char env_append[ENV_SIZE] = {0}, append_added = 0;
17157: char comspec_added = 0;
1.1.1.33 root 17158: char lastdrive_added = 0;
1.1.1.32 root 17159: char env_msdos_path[ENV_SIZE] = {0};
17160: char env_path[ENV_SIZE] = {0}, path_added = 0;
1.1.1.33 root 17161: char prompt_added = 0;
1.1.1.32 root 17162: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
1.1.1.33 root 17163: char tz_added = 0;
1.1.1.45 root 17164: const char *path, *short_path;
1.1.1.32 root 17165:
17166: if((path = getenv("MSDOS_APPEND")) != NULL) {
17167: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17168: strcpy(env_append, short_path);
17169: }
17170: }
17171: if((path = getenv("APPEND")) != NULL) {
17172: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17173: if(env_append[0] != '\0') {
17174: strcat(env_append, ";");
17175: }
17176: strcat(env_append, short_path);
17177: }
17178: }
17179:
17180: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
17181: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17182: strcpy(comspec_path, short_path);
17183: }
17184: }
17185: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
17186: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17187: strcpy(comspec_path, short_path);
17188: }
17189: }
1.1 root 17190:
1.1.1.28 root 17191: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32 root 17192: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17193: strcpy(env_msdos_path, short_path);
17194: strcpy(env_path, short_path);
1.1.1.14 root 17195: }
17196: }
1.1.1.28 root 17197: if((path = getenv("PATH")) != NULL) {
1.1.1.32 root 17198: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17199: if(env_path[0] != '\0') {
17200: strcat(env_path, ";");
17201: }
17202: strcat(env_path, short_path);
1.1.1.9 root 17203: }
17204: }
1.1.1.32 root 17205:
17206: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
17207: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 17208: }
1.1.1.32 root 17209: for(int i = 0; i < 4; i++) {
17210: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
17211: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
17212: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
17213: strcpy(env_temp, short_path);
17214: break;
17215: }
17216: }
1.1.1.24 root 17217: }
1.1.1.32 root 17218:
1.1.1.9 root 17219: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 17220: // lower to upper
1.1.1.28 root 17221: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 17222: strcpy(tmp, *p);
17223: for(int i = 0;; i++) {
17224: if(tmp[i] == '=') {
17225: tmp[i] = '\0';
17226: sprintf(name, ";%s;", tmp);
1.1.1.25 root 17227: my_strupr(name);
1.1 root 17228: tmp[i] = '=';
17229: break;
17230: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 17231: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 17232: }
17233: }
1.1.1.33 root 17234: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
17235: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
17236: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 17237: // ignore non standard environments
17238: } else {
1.1.1.33 root 17239: if(strncmp(tmp, "APPEND=", 7) == 0) {
1.1.1.32 root 17240: if(env_append[0] != '\0') {
17241: sprintf(tmp, "APPEND=%s", env_append);
17242: } else {
17243: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
17244: }
17245: append_added = 1;
17246: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 17247: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32 root 17248: comspec_added = 1;
1.1.1.33 root 17249: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
17250: char *env = getenv("MSDOS_LASTDRIVE");
17251: if(env != NULL) {
17252: sprintf(tmp, "LASTDRIVE=%s", env);
17253: }
17254: lastdrive_added = 1;
17255: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
1.1.1.28 root 17256: if(env_msdos_path[0] != '\0') {
17257: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
17258: } else {
17259: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
17260: }
1.1.1.33 root 17261: } else if(strncmp(tmp, "PATH=", 5) == 0) {
1.1.1.28 root 17262: if(env_path[0] != '\0') {
17263: sprintf(tmp, "PATH=%s", env_path);
17264: } else {
17265: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
17266: }
1.1.1.32 root 17267: path_added = 1;
1.1.1.33 root 17268: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
17269: prompt_added = 1;
1.1.1.28 root 17270: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
17271: if(env_temp[0] != '\0') {
17272: sprintf(tmp, "TEMP=%s", env_temp);
17273: } else {
17274: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
17275: }
1.1.1.32 root 17276: temp_added = 1;
1.1.1.33 root 17277: } else if(strncmp(tmp, "TMP=", 4) == 0) {
1.1.1.28 root 17278: if(env_temp[0] != '\0') {
17279: sprintf(tmp, "TMP=%s", env_temp);
17280: } else {
17281: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 17282: }
1.1.1.32 root 17283: tmp_added = 1;
1.1.1.33 root 17284: } else if(strncmp(tmp, "TZ=", 3) == 0) {
17285: char *env = getenv("MSDOS_TZ");
17286: if(env != NULL) {
17287: sprintf(tmp, "TZ=%s", env);
17288: }
17289: tz_added = 1;
1.1 root 17290: }
17291: int len = strlen(tmp);
1.1.1.14 root 17292: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 17293: fatalerror("too many environments\n");
17294: }
17295: memcpy(mem + (seg << 4) + ofs, tmp, len);
17296: ofs += len + 1;
17297: }
17298: }
1.1.1.32 root 17299: if(!append_added && env_append[0] != '\0') {
17300: #define SET_ENV(name, value) { \
17301: char tmp[ENV_SIZE]; \
17302: sprintf(tmp, "%s=%s", name, value); \
17303: int len = strlen(tmp); \
17304: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
17305: fatalerror("too many environments\n"); \
17306: } \
17307: memcpy(mem + (seg << 4) + ofs, tmp, len); \
17308: ofs += len + 1; \
17309: }
17310: SET_ENV("APPEND", env_append);
17311: }
17312: if(!comspec_added) {
17313: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
17314: }
1.1.1.33 root 17315: if(!lastdrive_added) {
17316: SET_ENV("LASTDRIVE", "Z");
17317: }
1.1.1.32 root 17318: if(!path_added) {
17319: SET_ENV("PATH", env_path);
17320: }
1.1.1.33 root 17321: if(!prompt_added) {
17322: SET_ENV("PROMPT", "$P$G");
17323: }
1.1.1.32 root 17324: if(!temp_added) {
17325: SET_ENV("TEMP", env_temp);
17326: }
17327: if(!tmp_added) {
17328: SET_ENV("TMP", env_temp);
17329: }
1.1.1.33 root 17330: if(!tz_added) {
17331: TIME_ZONE_INFORMATION tzi;
17332: HKEY hKey, hSubKey;
17333: char tzi_std_name[64];
17334: char tz_std[8] = "GMT";
17335: char tz_dlt[8] = "GST";
17336: char tz_value[32];
17337:
17338: // timezone name from GetTimeZoneInformation may not be english
17339: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
17340: setlocale(LC_CTYPE, "");
17341: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
17342:
17343: // get english timezone name from registry
17344: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
17345: for(DWORD i = 0; !tz_added; i++) {
17346: char reg_name[256], sub_key[1024], std_name[256];
17347: DWORD size;
17348: FILETIME ftTime;
17349: LONG result = RegEnumKeyEx(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
17350:
17351: if(result == ERROR_SUCCESS) {
17352: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
17353: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
17354: if(RegQueryValueEx(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
17355: // search english timezone name from table
1.1.1.37 root 17356: if(strcmp(std_name, tzi_std_name) == 0) {
1.1.1.33 root 17357: for(int j = 0; j < array_length(tz_table); j++) {
17358: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
17359: if(tz_table[j].std != NULL) {
17360: strcpy(tz_std, tz_table[j].std);
17361: }
17362: if(tz_table[j].dlt != NULL) {
17363: strcpy(tz_dlt, tz_table[j].dlt);
17364: }
17365: tz_added = 1;
17366: break;
17367: }
17368: }
17369: }
17370: }
17371: RegCloseKey(hSubKey);
17372: }
17373: } else if(result == ERROR_NO_MORE_ITEMS) {
17374: break;
17375: }
17376: }
17377: RegCloseKey(hKey);
17378: }
17379: if((tzi.Bias % 60) != 0) {
17380: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
17381: } else {
17382: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
17383: }
17384: if(daylight) {
17385: strcat(tz_value, tz_dlt);
17386: }
17387: SET_ENV("TZ", tz_value);
17388: }
1.1 root 17389: seg += (ENV_SIZE >> 4);
17390:
17391: // psp
1.1.1.33 root 17392: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
1.1 root 17393: current_psp = seg;
1.1.1.35 root 17394: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
17395: psp->parent_psp = current_psp;
1.1 root 17396: seg += (PSP_SIZE >> 4);
17397:
1.1.1.19 root 17398: // first free mcb in conventional memory
1.1.1.33 root 17399: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 17400: first_mcb = seg;
17401:
1.1.1.19 root 17402: // dummy mcb to link to umb
1.1.1.33 root 17403: #if 0
1.1.1.39 root 17404: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); // link umb
1.1.1.33 root 17405: #else
1.1.1.39 root 17406: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); // unlink umb
1.1.1.33 root 17407: #endif
1.1.1.19 root 17408:
17409: // first free mcb in upper memory block
1.1.1.8 root 17410: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 17411:
1.1.1.29 root 17412: #ifdef SUPPORT_HMA
17413: // first free mcb in high memory area
17414: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
17415: #endif
17416:
1.1.1.26 root 17417: // interrupt vector
17418: for(int i = 0; i < 0x80; i++) {
17419: *(UINT16 *)(mem + 4 * i + 0) = i;
17420: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
17421: }
1.1.1.49! root 17422: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffc:0018 irq0 (system timer)
! 17423: *(UINT16 *)(mem + 4 * 0x08 + 2) = DUMMY_TOP >> 4;
1.1.1.26 root 17424: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
17425: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
17426: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
17427: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
1.1.1.49! root 17428: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffc:0000 irq12 (mouse)
! 17429: *(UINT16 *)(mem + 4 * 0x74 + 2) = DUMMY_TOP >> 4;
1.1.1.26 root 17430:
1.1.1.29 root 17431: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 17432: static const struct {
17433: UINT16 attributes;
17434: char *dev_name;
17435: } dummy_devices[] = {
17436: {0x8013, "CON "},
17437: {0x8000, "AUX "},
17438: {0xa0c0, "PRN "},
17439: {0x8008, "CLOCK$ "},
17440: {0x8000, "COM1 "},
17441: {0xa0c0, "LPT1 "},
17442: {0xa0c0, "LPT2 "},
17443: {0xa0c0, "LPT3 "},
17444: {0x8000, "COM2 "},
17445: {0x8000, "COM3 "},
17446: {0x8000, "COM4 "},
1.1.1.30 root 17447: // {0xc000, "CONFIG$ "},
17448: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 17449: };
17450: static const UINT8 dummy_device_routine[] = {
17451: // from NUL device of Windows 98 SE
17452: // or word ptr ES:[BX+03],0100
17453: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
17454: // retf
17455: 0xcb,
17456: };
1.1.1.29 root 17457: device_t *last = NULL;
1.1.1.32 root 17458: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 17459: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 17460: device->next_driver.w.l = 22 + 18 * (i + 1);
17461: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 17462: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 17463: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
17464: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 17465: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 17466: last = device;
17467: }
17468: if(last != NULL) {
17469: last->next_driver.w.l = 0;
17470: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 17471: }
1.1.1.29 root 17472: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 17473:
1.1.1.25 root 17474: // dos info
17475: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
17476: dos_info->magic_word = 1;
17477: dos_info->first_mcb = MEMORY_TOP >> 4;
17478: dos_info->first_dpb.w.l = 0;
17479: dos_info->first_dpb.w.h = DPB_TOP >> 4;
17480: dos_info->first_sft.w.l = 0;
17481: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.41 root 17482: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 4th device in IO.SYS
1.1.1.25 root 17483: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 17484: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 17485: dos_info->con_device.w.h = DEVICE_TOP >> 4;
17486: dos_info->max_sector_len = 512;
17487: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
17488: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
17489: dos_info->cds.w.l = 0;
17490: dos_info->cds.w.h = CDS_TOP >> 4;
17491: dos_info->fcb_table.w.l = 0;
17492: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
17493: dos_info->last_drive = 'Z' - 'A' + 1;
17494: dos_info->buffers_x = 20;
17495: dos_info->buffers_y = 0;
17496: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 17497: dos_info->nul_device.next_driver.w.l = 22;
17498: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 17499: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 17500: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
17501: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 17502: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
17503: dos_info->disk_buf_heads.w.l = 0;
17504: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.39 root 17505: dos_info->umb_linked = (((mcb_t *)(mem + MEMORY_END - 16))->mz == 'M' ? 0x01 : 0x00);
1.1.1.25 root 17506: dos_info->first_umb_fcb = UMB_TOP >> 4;
17507: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 17508: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 17509:
17510: char *env;
17511: if((env = getenv("LASTDRIVE")) != NULL) {
17512: if(env[0] >= 'A' && env[0] <= 'Z') {
17513: dos_info->last_drive = env[0] - 'A' + 1;
17514: } else if(env[0] >= 'a' && env[0] <= 'z') {
17515: dos_info->last_drive = env[0] - 'a' + 1;
17516: }
17517: }
17518: if((env = getenv("windir")) != NULL) {
17519: if(env[0] >= 'A' && env[0] <= 'Z') {
17520: dos_info->boot_drive = env[0] - 'A' + 1;
17521: } else if(env[0] >= 'a' && env[0] <= 'z') {
17522: dos_info->boot_drive = env[0] - 'a' + 1;
17523: }
17524: }
17525: #if defined(HAS_I386)
17526: dos_info->i386_or_later = 1;
17527: #else
17528: dos_info->i386_or_later = 0;
17529: #endif
17530: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
17531:
1.1.1.27 root 17532: // ems (int 67h) and xms
1.1.1.25 root 17533: device_t *xms_device = (device_t *)(mem + XMS_TOP);
17534: xms_device->next_driver.w.l = 0xffff;
17535: xms_device->next_driver.w.h = 0xffff;
17536: xms_device->attributes = 0xc000;
1.1.1.29 root 17537: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
17538: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 17539: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
17540:
1.1.1.26 root 17541: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
17542: mem[XMS_TOP + 0x13] = 0x68;
17543: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 17544: #ifdef SUPPORT_XMS
17545: if(support_xms) {
1.1.1.26 root 17546: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
17547: mem[XMS_TOP + 0x16] = 0x69;
17548: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 17549: } else
17550: #endif
1.1.1.26 root 17551: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 17552: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 17553:
1.1.1.26 root 17554: // irq12 routine (mouse)
1.1.1.49! root 17555: mem[DUMMY_TOP + 0x00] = 0xcd; // int 6ah (dummy)
! 17556: mem[DUMMY_TOP + 0x01] = 0x6a;
! 17557: mem[DUMMY_TOP + 0x02] = 0x9a; // call far mouse
! 17558: mem[DUMMY_TOP + 0x03] = 0xff;
! 17559: mem[DUMMY_TOP + 0x04] = 0xff;
! 17560: mem[DUMMY_TOP + 0x05] = 0xff;
! 17561: mem[DUMMY_TOP + 0x06] = 0xff;
! 17562: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy)
! 17563: mem[DUMMY_TOP + 0x08] = 0x6b;
! 17564: mem[DUMMY_TOP + 0x09] = 0xcf; // iret
1.1.1.24 root 17565:
1.1.1.27 root 17566: // case map routine
1.1.1.49! root 17567: mem[DUMMY_TOP + 0x0a] = 0xcd; // int 6ch (dummy)
! 17568: mem[DUMMY_TOP + 0x0b] = 0x6c;
! 17569: mem[DUMMY_TOP + 0x0c] = 0xcb; // retf
1.1.1.27 root 17570:
17571: // font read routine
1.1.1.49! root 17572: mem[DUMMY_TOP + 0x0d] = 0xcd; // int 6dh (dummy)
! 17573: mem[DUMMY_TOP + 0x0e] = 0x6d;
! 17574: mem[DUMMY_TOP + 0x0f] = 0xcb; // retf
1.1.1.19 root 17575:
1.1.1.32 root 17576: // error message read routine
1.1.1.49! root 17577: mem[DUMMY_TOP + 0x10] = 0xcd; // int 6eh (dummy)
! 17578: mem[DUMMY_TOP + 0x11] = 0x6e;
! 17579: mem[DUMMY_TOP + 0x12] = 0xcb; // retf
1.1.1.32 root 17580:
1.1.1.35 root 17581: // dummy loop to wait BIOS/DOS service is done
1.1.1.49! root 17582: mem[DUMMY_TOP + 0x13] = 0xe6; // out f7h, al
! 17583: mem[DUMMY_TOP + 0x14] = 0xf7;
! 17584: mem[DUMMY_TOP + 0x15] = 0x78; // js/jns -4
! 17585: mem[DUMMY_TOP + 0x16] = 0xfc;
! 17586: mem[DUMMY_TOP + 0x17] = 0xcb; // retf
1.1.1.35 root 17587:
1.1.1.26 root 17588: // irq0 routine (system time)
1.1.1.49! root 17589: mem[DUMMY_TOP + 0x18] = 0xcd; // int 1ch
! 17590: mem[DUMMY_TOP + 0x19] = 0x1c;
! 17591: mem[DUMMY_TOP + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008
! 17592: mem[DUMMY_TOP + 0x1b] = 0x08;
! 17593: mem[DUMMY_TOP + 0x1c] = 0x00;
! 17594: mem[DUMMY_TOP + 0x1d] = ((IRET_TOP >> 4) ) & 0xff;
! 17595: mem[DUMMY_TOP + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff;
! 17596:
! 17597: // alter page map and call routine
! 17598: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far
! 17599: mem[DUMMY_TOP + 0x20] = 0xff;
! 17600: mem[DUMMY_TOP + 0x21] = 0xff;
! 17601: mem[DUMMY_TOP + 0x22] = 0xff;
! 17602: mem[DUMMY_TOP + 0x23] = 0xff;
! 17603: mem[DUMMY_TOP + 0x24] = 0xcd; // int 6fh (dummy)
! 17604: mem[DUMMY_TOP + 0x25] = 0x6f;
! 17605: mem[DUMMY_TOP + 0x26] = 0xcb; // retf
1.1.1.14 root 17606:
1.1.1.26 root 17607: // boot routine
1.1.1.49! root 17608: mem[0xffff0 + 0x00] = 0xf4; // halt
! 17609: mem[0xffff0 + 0x05] = '0'; // rom date
! 17610: mem[0xffff0 + 0x06] = '2';
! 17611: mem[0xffff0 + 0x07] = '/';
! 17612: mem[0xffff0 + 0x08] = '2';
! 17613: mem[0xffff0 + 0x09] = '2';
! 17614: mem[0xffff0 + 0x0a] = '/';
! 17615: mem[0xffff0 + 0x0b] = '0';
! 17616: mem[0xffff0 + 0x0c] = '6';
! 17617: mem[0xffff0 + 0x0e] = 0xfc; // machine id
! 17618: mem[0xffff0 + 0x0f] = 0x00;
1.1.1.24 root 17619:
1.1 root 17620: // param block
17621: // + 0: param block (22bytes)
17622: // +24: fcb1/2 (20bytes)
17623: // +44: command tail (128bytes)
17624: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
17625: param->env_seg = 0;
17626: param->cmd_line.w.l = 44;
17627: param->cmd_line.w.h = (WORK_TOP >> 4);
17628: param->fcb1.w.l = 24;
17629: param->fcb1.w.h = (WORK_TOP >> 4);
17630: param->fcb2.w.l = 24;
17631: param->fcb2.w.h = (WORK_TOP >> 4);
17632:
17633: memset(mem + WORK_TOP + 24, 0x20, 20);
17634:
17635: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
17636: if(argc > 1) {
17637: sprintf(cmd_line->cmd, " %s", argv[1]);
17638: for(int i = 2; i < argc; i++) {
17639: char tmp[128];
17640: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
17641: strcpy(cmd_line->cmd, tmp);
17642: }
17643: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
17644: } else {
17645: cmd_line->len = 0;
17646: }
17647: cmd_line->cmd[cmd_line->len] = 0x0d;
17648:
17649: // system file table
1.1.1.21 root 17650: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
17651: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 17652:
1.1.1.19 root 17653: // disk buffer header (from DOSBox)
17654: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
17655: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
17656: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
17657: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
17658: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
17659:
1.1 root 17660: // fcb table
17661: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 17662: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 17663:
1.1.1.41 root 17664: // drive parameter block
1.1.1.42 root 17665: for(int i = 0; i < 2; i++) {
1.1.1.43 root 17666: // may be a floppy drive
1.1.1.44 root 17667: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * i);
17668: sprintf(cds->path_name, "%c:\\", 'A' + i);
17669: cds->drive_attrib = 0x4000; // physical drive
17670: cds->dpb_ptr.w.l = sizeof(dpb_t) * i;
17671: cds->dpb_ptr.w.h = DPB_TOP >> 4;
17672: cds->word_1 = cds->word_2 = cds->word_3 = 0xffff;
17673: cds->bs_offset = 2;
17674:
1.1.1.41 root 17675: dpb_t *dpb = (dpb_t *)(mem + DPB_TOP + sizeof(dpb_t) * i);
17676: dpb->drive_num = i;
17677: dpb->unit_num = i;
1.1.1.43 root 17678: dpb->next_dpb_ofs = /*(i == 25) ? 0xffff : */sizeof(dpb_t) * (i + 1);
17679: dpb->next_dpb_seg = /*(i == 25) ? 0xffff : */DPB_TOP >> 4;
1.1.1.42 root 17680: }
17681: for(int i = 2; i < 26; i++) {
1.1.1.44 root 17682: msdos_cds_update(i);
1.1.1.42 root 17683: UINT16 seg, ofs;
17684: msdos_drive_param_block_update(i, &seg, &ofs, 1);
1.1.1.41 root 17685: }
17686:
1.1.1.17 root 17687: // nls stuff
17688: msdos_nls_tables_init();
1.1 root 17689:
17690: // execute command
1.1.1.28 root 17691: try {
17692: if(msdos_process_exec(argv[0], param, 0)) {
17693: fatalerror("'%s' not found\n", argv[0]);
17694: }
17695: } catch(...) {
17696: // we should not reach here :-(
17697: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 17698: }
17699: retval = 0;
17700: return(0);
17701: }
17702:
17703: #define remove_std_file(path) { \
17704: int fd = _open(path, _O_RDONLY | _O_BINARY); \
17705: if(fd != -1) { \
17706: _lseek(fd, 0, SEEK_END); \
17707: int size = _tell(fd); \
17708: _close(fd); \
17709: if(size == 0) { \
17710: remove(path); \
17711: } \
17712: } \
17713: }
17714:
17715: void msdos_finish()
17716: {
17717: for(int i = 0; i < MAX_FILES; i++) {
17718: if(file_handler[i].valid) {
17719: _close(i);
17720: }
17721: }
1.1.1.21 root 17722: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 17723: remove_std_file("stdaux.txt");
1.1.1.21 root 17724: #endif
1.1.1.30 root 17725: #ifdef SUPPORT_XMS
17726: msdos_xms_finish();
17727: #endif
1.1 root 17728: msdos_dbcs_table_finish();
17729: }
17730:
17731: /* ----------------------------------------------------------------------------
17732: PC/AT hardware emulation
17733: ---------------------------------------------------------------------------- */
17734:
17735: void hardware_init()
17736: {
1.1.1.3 root 17737: CPU_INIT_CALL(CPU_MODEL);
1.1 root 17738: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 17739: m_IF = 1;
1.1.1.3 root 17740: #if defined(HAS_I386)
1.1 root 17741: cpu_type = (REG32(EDX) >> 8) & 0x0f;
17742: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 17743: #endif
17744: i386_set_a20_line(0);
1.1.1.14 root 17745:
1.1.1.19 root 17746: ems_init();
1.1.1.25 root 17747: dma_init();
1.1 root 17748: pic_init();
1.1.1.25 root 17749: pio_init();
1.1.1.8 root 17750: #ifdef PIT_ALWAYS_RUNNING
17751: pit_init();
17752: #else
1.1 root 17753: pit_active = 0;
17754: #endif
1.1.1.25 root 17755: sio_init();
1.1.1.8 root 17756: cmos_init();
17757: kbd_init();
1.1 root 17758: }
17759:
1.1.1.10 root 17760: void hardware_finish()
17761: {
17762: #if defined(HAS_I386)
17763: vtlb_free(m_vtlb);
17764: #endif
1.1.1.19 root 17765: ems_finish();
1.1.1.37 root 17766: pio_finish();
1.1.1.25 root 17767: sio_finish();
1.1.1.10 root 17768: }
17769:
1.1.1.28 root 17770: void hardware_release()
17771: {
17772: // release hardware resources when this program will be terminated abnormally
17773: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 17774: if(fp_debug_log != NULL) {
17775: fclose(fp_debug_log);
17776: fp_debug_log = NULL;
1.1.1.28 root 17777: }
17778: #endif
17779: #if defined(HAS_I386)
17780: vtlb_free(m_vtlb);
17781: #endif
17782: ems_release();
1.1.1.37 root 17783: pio_release();
1.1.1.28 root 17784: sio_release();
17785: }
17786:
1.1 root 17787: void hardware_run()
17788: {
1.1.1.22 root 17789: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 17790: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.33 root 17791: fp_debug_log = fopen("debug.log", "w");
1.1.1.22 root 17792: #endif
1.1.1.3 root 17793: while(!m_halted) {
17794: #if defined(HAS_I386)
1.1 root 17795: CPU_EXECUTE_CALL(i386);
1.1.1.14 root 17796: if(m_eip != m_prev_eip) {
1.1.1.35 root 17797: idle_ops++;
17798: }
1.1.1.14 root 17799: #else
1.1.1.35 root 17800: CPU_EXECUTE_CALL(CPU_MODEL);
1.1.1.14 root 17801: if(m_pc != m_prevpc) {
1.1.1.35 root 17802: idle_ops++;
1.1.1.14 root 17803: }
1.1.1.35 root 17804: #endif
17805: if(++update_ops == UPDATE_OPS) {
1.1 root 17806: hardware_update();
1.1.1.35 root 17807: update_ops = 0;
1.1 root 17808: }
17809: }
1.1.1.22 root 17810: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 17811: if(fp_debug_log != NULL) {
17812: fclose(fp_debug_log);
17813: fp_debug_log = NULL;
1.1.1.28 root 17814: }
1.1.1.22 root 17815: #endif
1.1 root 17816: }
17817:
17818: void hardware_update()
17819: {
1.1.1.8 root 17820: static UINT32 prev_time = 0;
17821: UINT32 cur_time = timeGetTime();
17822:
17823: if(prev_time != cur_time) {
17824: // update pit and raise irq0
17825: #ifndef PIT_ALWAYS_RUNNING
17826: if(pit_active)
17827: #endif
17828: {
17829: if(pit_run(0, cur_time)) {
17830: pic_req(0, 0, 1);
17831: }
17832: pit_run(1, cur_time);
17833: pit_run(2, cur_time);
17834: }
1.1.1.24 root 17835:
1.1.1.25 root 17836: // update sio and raise irq4/3
1.1.1.29 root 17837: for(int c = 0; c < 4; c++) {
1.1.1.25 root 17838: sio_update(c);
17839: }
17840:
1.1.1.24 root 17841: // update keyboard and mouse
1.1.1.14 root 17842: static UINT32 prev_tick = 0;
17843: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 17844:
1.1.1.14 root 17845: if(prev_tick != cur_tick) {
17846: // update keyboard flags
17847: UINT8 state;
1.1.1.24 root 17848: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
17849: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
17850: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
17851: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
17852: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
17853: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
17854: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
17855: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 17856: mem[0x417] = state;
17857: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
17858: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
17859: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
17860: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 17861: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
17862: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 17863: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
17864: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
17865: mem[0x418] = state;
17866:
1.1.1.24 root 17867: // update console input if needed
1.1.1.34 root 17868: if(!key_changed || mouse.hidden == 0) {
1.1.1.24 root 17869: update_console_input();
17870: }
17871:
17872: // raise irq1 if key is pressed/released
17873: if(key_changed) {
1.1.1.8 root 17874: pic_req(0, 1, 1);
1.1.1.24 root 17875: key_changed = false;
17876: }
17877:
17878: // raise irq12 if mouse status is changed
1.1.1.43 root 17879: if((mouse.status & mouse.call_mask) && mouse.call_addr.dw) {
17880: mouse.status_irq = mouse.status & mouse.call_mask;
17881: mouse.status_irq_alt = 0; // ???
1.1.1.24 root 17882: mouse.status &= ~mouse.call_mask;
1.1.1.43 root 17883: pic_req(1, 4, 1);
17884: } else {
17885: for(int i = 0; i < 8; i++) {
17886: if((mouse.status_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
17887: mouse.status_irq = 0; // ???
17888: mouse.status_irq_alt = 0;
17889: for(int j = 0; j < 8; j++) {
17890: if((mouse.status_alt & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
17891: mouse.status_irq_alt |= (1 << j);
17892: mouse.status_alt &= ~(1 << j);
17893: }
17894: }
17895: pic_req(1, 4, 1);
17896: break;
17897: }
17898: }
1.1.1.8 root 17899: }
1.1.1.24 root 17900:
1.1.1.14 root 17901: prev_tick = cur_tick;
1.1.1.8 root 17902: }
1.1.1.24 root 17903:
1.1.1.19 root 17904: // update daily timer counter
17905: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 17906:
1.1.1.8 root 17907: prev_time = cur_time;
1.1 root 17908: }
17909: }
17910:
1.1.1.19 root 17911: // ems
17912:
17913: void ems_init()
17914: {
17915: memset(ems_handles, 0, sizeof(ems_handles));
17916: memset(ems_pages, 0, sizeof(ems_pages));
17917: free_ems_pages = MAX_EMS_PAGES;
17918: }
17919:
17920: void ems_finish()
17921: {
1.1.1.28 root 17922: ems_release();
17923: }
17924:
17925: void ems_release()
17926: {
1.1.1.31 root 17927: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 17928: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 17929: free(ems_handles[i].buffer);
17930: ems_handles[i].buffer = NULL;
17931: }
17932: }
17933: }
17934:
17935: void ems_allocate_pages(int handle, int pages)
17936: {
17937: if(pages > 0) {
17938: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
17939: } else {
17940: ems_handles[handle].buffer = NULL;
17941: }
17942: ems_handles[handle].pages = pages;
17943: ems_handles[handle].allocated = true;
17944: free_ems_pages -= pages;
17945: }
17946:
17947: void ems_reallocate_pages(int handle, int pages)
17948: {
17949: if(ems_handles[handle].allocated) {
17950: if(ems_handles[handle].pages != pages) {
17951: UINT8 *new_buffer = NULL;
17952:
17953: if(pages > 0) {
17954: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
17955: }
1.1.1.32 root 17956: if(ems_handles[handle].buffer != NULL) {
17957: if(new_buffer != NULL) {
1.1.1.19 root 17958: if(pages > ems_handles[handle].pages) {
17959: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
17960: } else {
17961: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
17962: }
17963: }
17964: free(ems_handles[handle].buffer);
17965: ems_handles[handle].buffer = NULL;
17966: }
17967: free_ems_pages += ems_handles[handle].pages;
17968:
17969: ems_handles[handle].buffer = new_buffer;
17970: ems_handles[handle].pages = pages;
17971: free_ems_pages -= pages;
17972: }
17973: } else {
17974: ems_allocate_pages(handle, pages);
17975: }
17976: }
17977:
17978: void ems_release_pages(int handle)
17979: {
17980: if(ems_handles[handle].allocated) {
1.1.1.32 root 17981: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 17982: free(ems_handles[handle].buffer);
17983: ems_handles[handle].buffer = NULL;
17984: }
17985: free_ems_pages += ems_handles[handle].pages;
17986: ems_handles[handle].allocated = false;
17987: }
17988: }
17989:
17990: void ems_map_page(int physical, int handle, int logical)
17991: {
17992: if(ems_pages[physical].mapped) {
17993: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
17994: return;
17995: }
17996: ems_unmap_page(physical);
17997: }
1.1.1.32 root 17998: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 17999: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
18000: }
18001: ems_pages[physical].handle = handle;
18002: ems_pages[physical].page = logical;
18003: ems_pages[physical].mapped = true;
18004: }
18005:
18006: void ems_unmap_page(int physical)
18007: {
18008: if(ems_pages[physical].mapped) {
18009: int handle = ems_pages[physical].handle;
18010: int logical = ems_pages[physical].page;
18011:
1.1.1.32 root 18012: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 18013: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
18014: }
18015: ems_pages[physical].mapped = false;
18016: }
18017: }
18018:
1.1.1.25 root 18019: // dma
1.1 root 18020:
1.1.1.25 root 18021: void dma_init()
1.1 root 18022: {
1.1.1.26 root 18023: memset(dma, 0, sizeof(dma));
1.1.1.25 root 18024: for(int c = 0; c < 2; c++) {
1.1.1.26 root 18025: // for(int ch = 0; ch < 4; ch++) {
18026: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
18027: // }
1.1.1.25 root 18028: dma_reset(c);
18029: }
1.1 root 18030: }
18031:
1.1.1.25 root 18032: void dma_reset(int c)
1.1 root 18033: {
1.1.1.25 root 18034: dma[c].low_high = false;
18035: dma[c].cmd = dma[c].req = dma[c].tc = 0;
18036: dma[c].mask = 0xff;
18037: }
18038:
18039: void dma_write(int c, UINT32 addr, UINT8 data)
18040: {
18041: int ch = (addr >> 1) & 3;
18042: UINT8 bit = 1 << (data & 3);
18043:
18044: switch(addr & 0x0f) {
18045: case 0x00: case 0x02: case 0x04: case 0x06:
18046: if(dma[c].low_high) {
18047: dma[c].ch[ch].bareg.b.h = data;
1.1 root 18048: } else {
1.1.1.25 root 18049: dma[c].ch[ch].bareg.b.l = data;
18050: }
18051: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
18052: dma[c].low_high = !dma[c].low_high;
18053: break;
18054: case 0x01: case 0x03: case 0x05: case 0x07:
18055: if(dma[c].low_high) {
18056: dma[c].ch[ch].bcreg.b.h = data;
18057: } else {
18058: dma[c].ch[ch].bcreg.b.l = data;
18059: }
18060: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
18061: dma[c].low_high = !dma[c].low_high;
18062: break;
18063: case 0x08:
18064: // command register
18065: dma[c].cmd = data;
18066: break;
18067: case 0x09:
18068: // dma[c].request register
18069: if(data & 4) {
18070: if(!(dma[c].req & bit)) {
18071: dma[c].req |= bit;
18072: // dma_run(c, ch);
18073: }
18074: } else {
18075: dma[c].req &= ~bit;
18076: }
18077: break;
18078: case 0x0a:
18079: // single mask register
18080: if(data & 4) {
18081: dma[c].mask |= bit;
18082: } else {
18083: dma[c].mask &= ~bit;
18084: }
18085: break;
18086: case 0x0b:
18087: // mode register
18088: dma[c].ch[data & 3].mode = data;
18089: break;
18090: case 0x0c:
18091: dma[c].low_high = false;
18092: break;
18093: case 0x0d:
18094: // clear master
18095: dma_reset(c);
18096: break;
18097: case 0x0e:
18098: // clear mask register
18099: dma[c].mask = 0;
18100: break;
18101: case 0x0f:
18102: // all mask register
18103: dma[c].mask = data & 0x0f;
18104: break;
18105: }
18106: }
18107:
18108: UINT8 dma_read(int c, UINT32 addr)
18109: {
18110: int ch = (addr >> 1) & 3;
18111: UINT8 val = 0xff;
18112:
18113: switch(addr & 0x0f) {
18114: case 0x00: case 0x02: case 0x04: case 0x06:
18115: if(dma[c].low_high) {
18116: val = dma[c].ch[ch].areg.b.h;
18117: } else {
18118: val = dma[c].ch[ch].areg.b.l;
18119: }
18120: dma[c].low_high = !dma[c].low_high;
18121: return(val);
18122: case 0x01: case 0x03: case 0x05: case 0x07:
18123: if(dma[c].low_high) {
18124: val = dma[c].ch[ch].creg.b.h;
18125: } else {
18126: val = dma[c].ch[ch].creg.b.l;
18127: }
18128: dma[c].low_high = !dma[c].low_high;
18129: return(val);
18130: case 0x08:
18131: // status register
18132: val = (dma[c].req << 4) | dma[c].tc;
18133: dma[c].tc = 0;
18134: return(val);
18135: case 0x0d:
1.1.1.26 root 18136: // temporary register (intel 82374 does not support)
1.1.1.25 root 18137: return(dma[c].tmp & 0xff);
1.1.1.26 root 18138: case 0x0f:
18139: // mask register (intel 82374 does support)
18140: return(dma[c].mask);
1.1.1.25 root 18141: }
18142: return(0xff);
18143: }
18144:
18145: void dma_page_write(int c, int ch, UINT8 data)
18146: {
18147: dma[c].ch[ch].pagereg = data;
18148: }
18149:
18150: UINT8 dma_page_read(int c, int ch)
18151: {
18152: return(dma[c].ch[ch].pagereg);
18153: }
18154:
18155: void dma_run(int c, int ch)
18156: {
18157: UINT8 bit = 1 << ch;
18158:
18159: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
18160: // execute dma
18161: while(dma[c].req & bit) {
18162: if(ch == 0 && (dma[c].cmd & 0x01)) {
18163: // memory -> memory
18164: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
18165: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
18166:
18167: if(c == 0) {
18168: dma[c].tmp = read_byte(saddr);
18169: write_byte(daddr, dma[c].tmp);
18170: } else {
18171: dma[c].tmp = read_word(saddr << 1);
18172: write_word(daddr << 1, dma[c].tmp);
18173: }
18174: if(!(dma[c].cmd & 0x02)) {
18175: if(dma[c].ch[0].mode & 0x20) {
18176: dma[c].ch[0].areg.w--;
18177: if(dma[c].ch[0].areg.w == 0xffff) {
18178: dma[c].ch[0].pagereg--;
18179: }
18180: } else {
18181: dma[c].ch[0].areg.w++;
18182: if(dma[c].ch[0].areg.w == 0) {
18183: dma[c].ch[0].pagereg++;
18184: }
18185: }
18186: }
18187: if(dma[c].ch[1].mode & 0x20) {
18188: dma[c].ch[1].areg.w--;
18189: if(dma[c].ch[1].areg.w == 0xffff) {
18190: dma[c].ch[1].pagereg--;
18191: }
18192: } else {
18193: dma[c].ch[1].areg.w++;
18194: if(dma[c].ch[1].areg.w == 0) {
18195: dma[c].ch[1].pagereg++;
18196: }
18197: }
18198:
18199: // check dma condition
18200: if(dma[c].ch[0].creg.w-- == 0) {
18201: if(dma[c].ch[0].mode & 0x10) {
18202: // self initialize
18203: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
18204: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
18205: } else {
18206: // dma[c].mask |= bit;
18207: }
18208: }
18209: if(dma[c].ch[1].creg.w-- == 0) {
18210: // terminal count
18211: if(dma[c].ch[1].mode & 0x10) {
18212: // self initialize
18213: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
18214: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
18215: } else {
18216: dma[c].mask |= bit;
18217: }
18218: dma[c].req &= ~bit;
18219: dma[c].tc |= bit;
18220: }
18221: } else {
18222: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
18223:
18224: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
18225: // verify
18226: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
18227: // io -> memory
18228: if(c == 0) {
18229: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
18230: write_byte(addr, dma[c].tmp);
18231: } else {
18232: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
18233: write_word(addr << 1, dma[c].tmp);
18234: }
18235: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
18236: // memory -> io
18237: if(c == 0) {
18238: dma[c].tmp = read_byte(addr);
18239: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
18240: } else {
18241: dma[c].tmp = read_word(addr << 1);
18242: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
18243: }
18244: }
18245: if(dma[c].ch[ch].mode & 0x20) {
18246: dma[c].ch[ch].areg.w--;
18247: if(dma[c].ch[ch].areg.w == 0xffff) {
18248: dma[c].ch[ch].pagereg--;
18249: }
18250: } else {
18251: dma[c].ch[ch].areg.w++;
18252: if(dma[c].ch[ch].areg.w == 0) {
18253: dma[c].ch[ch].pagereg++;
18254: }
18255: }
18256:
18257: // check dma condition
18258: if(dma[c].ch[ch].creg.w-- == 0) {
18259: // terminal count
18260: if(dma[c].ch[ch].mode & 0x10) {
18261: // self initialize
18262: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
18263: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
18264: } else {
18265: dma[c].mask |= bit;
18266: }
18267: dma[c].req &= ~bit;
18268: dma[c].tc |= bit;
18269: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
18270: // single mode
18271: break;
18272: }
18273: }
18274: }
18275: }
18276: }
18277:
18278: // pic
18279:
18280: void pic_init()
18281: {
18282: memset(pic, 0, sizeof(pic));
18283: pic[0].imr = pic[1].imr = 0xff;
18284:
18285: // from bochs bios
18286: pic_write(0, 0, 0x11); // icw1 = 11h
18287: pic_write(0, 1, 0x08); // icw2 = 08h
18288: pic_write(0, 1, 0x04); // icw3 = 04h
18289: pic_write(0, 1, 0x01); // icw4 = 01h
18290: pic_write(0, 1, 0xb8); // ocw1 = b8h
18291: pic_write(1, 0, 0x11); // icw1 = 11h
18292: pic_write(1, 1, 0x70); // icw2 = 70h
18293: pic_write(1, 1, 0x02); // icw3 = 02h
18294: pic_write(1, 1, 0x01); // icw4 = 01h
18295: }
18296:
18297: void pic_write(int c, UINT32 addr, UINT8 data)
18298: {
18299: if(addr & 1) {
18300: if(pic[c].icw2_r) {
18301: // icw2
18302: pic[c].icw2 = data;
18303: pic[c].icw2_r = 0;
18304: } else if(pic[c].icw3_r) {
18305: // icw3
18306: pic[c].icw3 = data;
18307: pic[c].icw3_r = 0;
18308: } else if(pic[c].icw4_r) {
18309: // icw4
18310: pic[c].icw4 = data;
18311: pic[c].icw4_r = 0;
18312: } else {
18313: // ocw1
1.1 root 18314: pic[c].imr = data;
18315: }
18316: } else {
18317: if(data & 0x10) {
18318: // icw1
18319: pic[c].icw1 = data;
18320: pic[c].icw2_r = 1;
18321: pic[c].icw3_r = (data & 2) ? 0 : 1;
18322: pic[c].icw4_r = data & 1;
18323: pic[c].irr = 0;
18324: pic[c].isr = 0;
18325: pic[c].imr = 0;
18326: pic[c].prio = 0;
18327: if(!(pic[c].icw1 & 1)) {
18328: pic[c].icw4 = 0;
18329: }
18330: pic[c].ocw3 = 0;
18331: } else if(data & 8) {
18332: // ocw3
18333: if(!(data & 2)) {
18334: data = (data & ~1) | (pic[c].ocw3 & 1);
18335: }
18336: if(!(data & 0x40)) {
18337: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
18338: }
18339: pic[c].ocw3 = data;
18340: } else {
18341: // ocw2
18342: int level = 0;
18343: if(data & 0x40) {
18344: level = data & 7;
18345: } else {
18346: if(!pic[c].isr) {
18347: return;
18348: }
18349: level = pic[c].prio;
18350: while(!(pic[c].isr & (1 << level))) {
18351: level = (level + 1) & 7;
18352: }
18353: }
18354: if(data & 0x80) {
18355: pic[c].prio = (level + 1) & 7;
18356: }
18357: if(data & 0x20) {
18358: pic[c].isr &= ~(1 << level);
18359: }
18360: }
18361: }
18362: pic_update();
18363: }
18364:
18365: UINT8 pic_read(int c, UINT32 addr)
18366: {
18367: if(addr & 1) {
18368: return(pic[c].imr);
18369: } else {
18370: // polling mode is not supported...
18371: //if(pic[c].ocw3 & 4) {
18372: // return ???;
18373: //}
18374: if(pic[c].ocw3 & 1) {
18375: return(pic[c].isr);
18376: } else {
18377: return(pic[c].irr);
18378: }
18379: }
18380: }
18381:
18382: void pic_req(int c, int level, int signal)
18383: {
18384: if(signal) {
18385: pic[c].irr |= (1 << level);
18386: } else {
18387: pic[c].irr &= ~(1 << level);
18388: }
18389: pic_update();
18390: }
18391:
18392: int pic_ack()
18393: {
18394: // ack (INTA=L)
18395: pic[pic_req_chip].isr |= pic_req_bit;
18396: pic[pic_req_chip].irr &= ~pic_req_bit;
18397: if(pic_req_chip > 0) {
18398: // update isr and irr of master
18399: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
18400: pic[pic_req_chip - 1].isr |= slave;
18401: pic[pic_req_chip - 1].irr &= ~slave;
18402: }
18403: //if(pic[pic_req_chip].icw4 & 1) {
18404: // 8086 mode
18405: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
18406: //} else {
18407: // // 8080 mode
18408: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
18409: // if(pic[pic_req_chip].icw1 & 4) {
18410: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
18411: // } else {
18412: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
18413: // }
18414: // vector = 0xcd | (addr << 8);
18415: //}
18416: if(pic[pic_req_chip].icw4 & 2) {
18417: // auto eoi
18418: pic[pic_req_chip].isr &= ~pic_req_bit;
18419: }
18420: return(vector);
18421: }
18422:
18423: void pic_update()
18424: {
18425: for(int c = 0; c < 2; c++) {
18426: UINT8 irr = pic[c].irr;
18427: if(c + 1 < 2) {
18428: // this is master
18429: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
18430: // request from slave
18431: irr |= 1 << (pic[c + 1].icw3 & 7);
18432: }
18433: }
18434: irr &= (~pic[c].imr);
18435: if(!irr) {
18436: break;
18437: }
18438: if(!(pic[c].ocw3 & 0x20)) {
18439: irr |= pic[c].isr;
18440: }
18441: int level = pic[c].prio;
18442: UINT8 bit = 1 << level;
18443: while(!(irr & bit)) {
18444: level = (level + 1) & 7;
18445: bit = 1 << level;
18446: }
18447: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
18448: // check slave
18449: continue;
18450: }
18451: if(pic[c].isr & bit) {
18452: break;
18453: }
18454: // interrupt request
18455: pic_req_chip = c;
18456: pic_req_level = level;
18457: pic_req_bit = bit;
1.1.1.3 root 18458: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 18459: return;
18460: }
1.1.1.3 root 18461: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 18462: }
1.1 root 18463:
1.1.1.25 root 18464: // pio
18465:
18466: void pio_init()
18467: {
1.1.1.38 root 18468: // bool conv_mode = (GetConsoleCP() == 932);
18469:
1.1.1.26 root 18470: memset(pio, 0, sizeof(pio));
1.1.1.37 root 18471:
1.1.1.25 root 18472: for(int c = 0; c < 2; c++) {
1.1.1.37 root 18473: pio[c].stat = 0xdf;
1.1.1.25 root 18474: pio[c].ctrl = 0x0c;
1.1.1.38 root 18475: // pio[c].conv_mode = conv_mode;
1.1.1.25 root 18476: }
18477: }
18478:
1.1.1.37 root 18479: void pio_finish()
18480: {
18481: pio_release();
18482: }
18483:
18484: void pio_release()
18485: {
18486: for(int c = 0; c < 2; c++) {
18487: if(pio[c].fp != NULL) {
1.1.1.38 root 18488: if(pio[c].jis_mode) {
18489: fputc(0x1c, pio[c].fp);
18490: fputc(0x2e, pio[c].fp);
18491: }
1.1.1.37 root 18492: fclose(pio[c].fp);
18493: pio[c].fp = NULL;
18494: }
18495: }
18496: }
18497:
1.1.1.25 root 18498: void pio_write(int c, UINT32 addr, UINT8 data)
18499: {
18500: switch(addr & 3) {
18501: case 0:
18502: pio[c].data = data;
18503: break;
18504: case 2:
1.1.1.37 root 18505: if((pio[c].ctrl & 0x01) && !(data & 0x01)) {
18506: // strobe H -> L
18507: if(pio[c].data == 0x0d && (data & 0x02)) {
18508: // auto feed
18509: printer_out(c, 0x0d);
18510: printer_out(c, 0x0a);
18511: } else {
18512: printer_out(c, pio[c].data);
18513: }
18514: pio[c].stat &= ~0x40; // set ack
18515: }
1.1.1.25 root 18516: pio[c].ctrl = data;
18517: break;
18518: }
18519: }
18520:
18521: UINT8 pio_read(int c, UINT32 addr)
18522: {
18523: switch(addr & 3) {
18524: case 0:
1.1.1.37 root 18525: if(pio[c].ctrl & 0x20) {
18526: // input mode
18527: return(0xff);
18528: }
1.1.1.25 root 18529: return(pio[c].data);
18530: case 1:
1.1.1.37 root 18531: {
18532: UINT8 stat = pio[c].stat;
18533: pio[c].stat |= 0x40; // clear ack
18534: return(stat);
18535: }
1.1.1.25 root 18536: case 2:
18537: return(pio[c].ctrl);
18538: }
18539: return(0xff);
18540: }
18541:
1.1.1.37 root 18542: void printer_out(int c, UINT8 data)
18543: {
18544: SYSTEMTIME time;
1.1.1.38 root 18545: bool jis_mode = false;
1.1.1.37 root 18546:
18547: GetLocalTime(&time);
18548:
18549: if(pio[c].fp != NULL) {
18550: // if at least 1000ms passed from last written, close the current file
18551: FILETIME ftime1;
18552: FILETIME ftime2;
18553: SystemTimeToFileTime(&pio[c].time, &ftime1);
18554: SystemTimeToFileTime(&time, &ftime2);
18555: INT64 *time1 = (INT64 *)&ftime1;
18556: INT64 *time2 = (INT64 *)&ftime2;
18557: INT64 msec = (*time2 - *time1) / 10000;
18558:
18559: if(msec >= 1000) {
1.1.1.38 root 18560: if(pio[c].jis_mode) {
18561: fputc(0x1c, pio[c].fp);
18562: fputc(0x2e, pio[c].fp);
18563: jis_mode = true;
18564: }
1.1.1.37 root 18565: fclose(pio[c].fp);
18566: pio[c].fp = NULL;
18567: }
18568: }
18569: if(pio[c].fp == NULL) {
18570: // create a new file in the temp folder
18571: char file_name[MAX_PATH];
18572:
18573: sprintf(file_name, "%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.PRN", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);
18574: if(GetTempPath(MAX_PATH, pio[c].path)) {
18575: strcat(pio[c].path, file_name);
18576: } else {
18577: strcpy(pio[c].path, file_name);
18578: }
1.1.1.38 root 18579: pio[c].fp = fopen(pio[c].path, "w+b");
1.1.1.37 root 18580: }
18581: if(pio[c].fp != NULL) {
1.1.1.38 root 18582: if(jis_mode) {
18583: fputc(0x1c, pio[c].fp);
18584: fputc(0x26, pio[c].fp);
18585: }
1.1.1.37 root 18586: fputc(data, pio[c].fp);
1.1.1.38 root 18587:
18588: // reopen file if 1ch 26h 1ch 2eh (kanji-on kanji-off) are written at the top
18589: if(data == 0x2e && ftell(pio[c].fp) == 4) {
18590: UINT8 buffer[4];
18591: fseek(pio[c].fp, 0, SEEK_SET);
18592: fread(buffer, 4, 1, pio[c].fp);
18593: if(buffer[0] == 0x1c && buffer[1] == 0x26 && buffer[2] == 0x1c/* && buffer[3] == 0x2e*/) {
18594: fclose(pio[c].fp);
18595: pio[c].fp = fopen(pio[c].path, "w+b");
18596: }
18597: }
1.1.1.37 root 18598: pio[c].time = time;
18599: }
18600: }
18601:
1.1 root 18602: // pit
18603:
1.1.1.22 root 18604: #define PIT_FREQ 1193182ULL
1.1 root 18605: #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)
18606:
18607: void pit_init()
18608: {
1.1.1.8 root 18609: memset(pit, 0, sizeof(pit));
1.1 root 18610: for(int ch = 0; ch < 3; ch++) {
18611: pit[ch].count = 0x10000;
18612: pit[ch].ctrl_reg = 0x34;
18613: pit[ch].mode = 3;
18614: }
18615:
18616: // from bochs bios
18617: pit_write(3, 0x34);
18618: pit_write(0, 0x00);
18619: pit_write(0, 0x00);
18620: }
18621:
18622: void pit_write(int ch, UINT8 val)
18623: {
1.1.1.8 root 18624: #ifndef PIT_ALWAYS_RUNNING
1.1 root 18625: if(!pit_active) {
18626: pit_active = 1;
18627: pit_init();
18628: }
1.1.1.8 root 18629: #endif
1.1 root 18630: switch(ch) {
18631: case 0:
18632: case 1:
18633: case 2:
18634: // write count register
18635: if(!pit[ch].low_write && !pit[ch].high_write) {
18636: if(pit[ch].ctrl_reg & 0x10) {
18637: pit[ch].low_write = 1;
18638: }
18639: if(pit[ch].ctrl_reg & 0x20) {
18640: pit[ch].high_write = 1;
18641: }
18642: }
18643: if(pit[ch].low_write) {
18644: pit[ch].count_reg = val;
18645: pit[ch].low_write = 0;
18646: } else if(pit[ch].high_write) {
18647: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
18648: pit[ch].count_reg = val << 8;
18649: } else {
18650: pit[ch].count_reg |= val << 8;
18651: }
18652: pit[ch].high_write = 0;
18653: }
18654: // start count
1.1.1.8 root 18655: if(!pit[ch].low_write && !pit[ch].high_write) {
18656: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
18657: pit[ch].count = PIT_COUNT_VALUE(ch);
18658: pit[ch].prev_time = timeGetTime();
18659: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 18660: }
18661: }
18662: break;
18663: case 3: // ctrl reg
18664: if((val & 0xc0) == 0xc0) {
18665: // i8254 read-back command
18666: for(ch = 0; ch < 3; ch++) {
18667: if(!(val & 0x10) && !pit[ch].status_latched) {
18668: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
18669: pit[ch].status_latched = 1;
18670: }
18671: if(!(val & 0x20) && !pit[ch].count_latched) {
18672: pit_latch_count(ch);
18673: }
18674: }
18675: break;
18676: }
18677: ch = (val >> 6) & 3;
18678: if(val & 0x30) {
1.1.1.35 root 18679: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
1.1 root 18680: pit[ch].mode = modes[(val >> 1) & 7];
18681: pit[ch].count_latched = 0;
18682: pit[ch].low_read = pit[ch].high_read = 0;
18683: pit[ch].low_write = pit[ch].high_write = 0;
18684: pit[ch].ctrl_reg = val;
18685: // stop count
1.1.1.8 root 18686: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 18687: pit[ch].count_reg = 0;
18688: } else if(!pit[ch].count_latched) {
18689: pit_latch_count(ch);
18690: }
18691: break;
18692: }
18693: }
18694:
18695: UINT8 pit_read(int ch)
18696: {
1.1.1.8 root 18697: #ifndef PIT_ALWAYS_RUNNING
1.1 root 18698: if(!pit_active) {
18699: pit_active = 1;
18700: pit_init();
18701: }
1.1.1.8 root 18702: #endif
1.1 root 18703: switch(ch) {
18704: case 0:
18705: case 1:
18706: case 2:
18707: if(pit[ch].status_latched) {
18708: pit[ch].status_latched = 0;
18709: return(pit[ch].status);
18710: }
18711: // if not latched, through current count
18712: if(!pit[ch].count_latched) {
18713: if(!pit[ch].low_read && !pit[ch].high_read) {
18714: pit_latch_count(ch);
18715: }
18716: }
18717: // return latched count
18718: if(pit[ch].low_read) {
18719: pit[ch].low_read = 0;
18720: if(!pit[ch].high_read) {
18721: pit[ch].count_latched = 0;
18722: }
18723: return(pit[ch].latch & 0xff);
18724: } else if(pit[ch].high_read) {
18725: pit[ch].high_read = 0;
18726: pit[ch].count_latched = 0;
18727: return((pit[ch].latch >> 8) & 0xff);
18728: }
18729: }
18730: return(0xff);
18731: }
18732:
1.1.1.8 root 18733: int pit_run(int ch, UINT32 cur_time)
1.1 root 18734: {
1.1.1.8 root 18735: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 18736: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 18737: pit[ch].prev_time = pit[ch].expired_time;
18738: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
18739: if(cur_time >= pit[ch].expired_time) {
18740: pit[ch].prev_time = cur_time;
18741: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 18742: }
1.1.1.8 root 18743: return(1);
1.1 root 18744: }
1.1.1.8 root 18745: return(0);
1.1 root 18746: }
18747:
18748: void pit_latch_count(int ch)
18749: {
1.1.1.8 root 18750: if(pit[ch].expired_time != 0) {
1.1.1.26 root 18751: UINT32 cur_time = timeGetTime();
1.1.1.8 root 18752: pit_run(ch, cur_time);
18753: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 18754: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
18755:
18756: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
18757: // decrement counter in 1msec period
18758: if(pit[ch].next_latch == 0) {
18759: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
18760: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
18761: }
18762: if(pit[ch].latch > pit[ch].next_latch) {
18763: pit[ch].latch--;
18764: }
18765: } else {
18766: pit[ch].prev_latch = pit[ch].latch = latch;
18767: pit[ch].next_latch = 0;
18768: }
1.1.1.8 root 18769: } else {
18770: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 18771: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 18772: }
18773: pit[ch].count_latched = 1;
18774: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
18775: // lower byte
18776: pit[ch].low_read = 1;
18777: pit[ch].high_read = 0;
18778: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
18779: // upper byte
18780: pit[ch].low_read = 0;
18781: pit[ch].high_read = 1;
18782: } else {
18783: // lower -> upper
1.1.1.14 root 18784: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 18785: }
18786: }
18787:
1.1.1.8 root 18788: int pit_get_expired_time(int ch)
1.1 root 18789: {
1.1.1.22 root 18790: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
18791: UINT64 val = pit[ch].accum >> 10;
18792: pit[ch].accum -= val << 10;
18793: return((val != 0) ? val : 1);
1.1.1.8 root 18794: }
18795:
1.1.1.25 root 18796: // sio
18797:
18798: void sio_init()
18799: {
1.1.1.26 root 18800: memset(sio, 0, sizeof(sio));
18801: memset(sio_mt, 0, sizeof(sio_mt));
18802:
1.1.1.29 root 18803: for(int c = 0; c < 4; c++) {
1.1.1.25 root 18804: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
18805: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
18806:
18807: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
18808: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 18809: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
18810: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 18811: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
18812: sio[c].irq_identify = 0x01; // no pending irq
18813:
18814: InitializeCriticalSection(&sio_mt[c].csSendData);
18815: InitializeCriticalSection(&sio_mt[c].csRecvData);
18816: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
18817: InitializeCriticalSection(&sio_mt[c].csLineStat);
18818: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
18819: InitializeCriticalSection(&sio_mt[c].csModemStat);
18820:
1.1.1.26 root 18821: if(sio_port_number[c] != 0) {
1.1.1.25 root 18822: sio[c].channel = c;
18823: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
18824: }
18825: }
18826: }
18827:
18828: void sio_finish()
18829: {
1.1.1.29 root 18830: for(int c = 0; c < 4; c++) {
1.1.1.25 root 18831: if(sio_mt[c].hThread != NULL) {
18832: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
18833: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 18834: sio_mt[c].hThread = NULL;
1.1.1.25 root 18835: }
18836: DeleteCriticalSection(&sio_mt[c].csSendData);
18837: DeleteCriticalSection(&sio_mt[c].csRecvData);
18838: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
18839: DeleteCriticalSection(&sio_mt[c].csLineStat);
18840: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
18841: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 18842: }
18843: sio_release();
18844: }
18845:
18846: void sio_release()
18847: {
1.1.1.29 root 18848: for(int c = 0; c < 4; c++) {
1.1.1.28 root 18849: // sio_thread() may access the resources :-(
1.1.1.32 root 18850: bool running = (sio_mt[c].hThread != NULL);
18851:
18852: if(running) {
18853: EnterCriticalSection(&sio_mt[c].csSendData);
18854: }
18855: if(sio[c].send_buffer != NULL) {
18856: sio[c].send_buffer->release();
18857: delete sio[c].send_buffer;
18858: sio[c].send_buffer = NULL;
18859: }
18860: if(running) {
18861: LeaveCriticalSection(&sio_mt[c].csSendData);
18862: EnterCriticalSection(&sio_mt[c].csRecvData);
18863: }
18864: if(sio[c].recv_buffer != NULL) {
18865: sio[c].recv_buffer->release();
18866: delete sio[c].recv_buffer;
18867: sio[c].recv_buffer = NULL;
18868: }
18869: if(running) {
18870: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 18871: }
1.1.1.25 root 18872: }
18873: }
18874:
18875: void sio_write(int c, UINT32 addr, UINT8 data)
18876: {
18877: switch(addr & 7) {
18878: case 0:
18879: if(sio[c].selector & 0x80) {
18880: if(sio[c].divisor.b.l != data) {
18881: EnterCriticalSection(&sio_mt[c].csLineCtrl);
18882: sio[c].divisor.b.l = data;
18883: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
18884: }
18885: } else {
18886: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 18887: if(sio[c].send_buffer != NULL) {
18888: sio[c].send_buffer->write(data);
18889: }
1.1.1.25 root 18890: // transmitter holding/shift registers are not empty
18891: sio[c].line_stat_buf &= ~0x60;
18892: LeaveCriticalSection(&sio_mt[c].csSendData);
18893:
18894: if(sio[c].irq_enable & 0x02) {
18895: sio_update_irq(c);
18896: }
18897: }
18898: break;
18899: case 1:
18900: if(sio[c].selector & 0x80) {
18901: if(sio[c].divisor.b.h != data) {
18902: EnterCriticalSection(&sio_mt[c].csLineCtrl);
18903: sio[c].divisor.b.h = data;
18904: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
18905: }
18906: } else {
18907: if(sio[c].irq_enable != data) {
18908: sio[c].irq_enable = data;
18909: sio_update_irq(c);
18910: }
18911: }
18912: break;
18913: case 3:
18914: {
18915: UINT8 line_ctrl = data & 0x3f;
18916: bool set_brk = ((data & 0x40) != 0);
18917:
18918: if(sio[c].line_ctrl != line_ctrl) {
18919: EnterCriticalSection(&sio_mt[c].csLineCtrl);
18920: sio[c].line_ctrl = line_ctrl;
18921: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
18922: }
18923: if(sio[c].set_brk != set_brk) {
18924: EnterCriticalSection(&sio_mt[c].csModemCtrl);
18925: sio[c].set_brk = set_brk;
18926: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
18927: }
18928: }
18929: sio[c].selector = data;
18930: break;
18931: case 4:
18932: {
18933: bool set_dtr = ((data & 0x01) != 0);
18934: bool set_rts = ((data & 0x02) != 0);
18935:
18936: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 18937: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 18938: sio[c].set_dtr = set_dtr;
18939: sio[c].set_rts = set_rts;
1.1.1.26 root 18940: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
18941:
18942: bool state_changed = false;
18943:
18944: EnterCriticalSection(&sio_mt[c].csModemStat);
18945: if(set_dtr) {
18946: sio[c].modem_stat |= 0x20; // dsr on
18947: } else {
18948: sio[c].modem_stat &= ~0x20; // dsr off
18949: }
18950: if(set_rts) {
18951: sio[c].modem_stat |= 0x10; // cts on
18952: } else {
18953: sio[c].modem_stat &= ~0x10; // cts off
18954: }
18955: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
18956: if(!(sio[c].modem_stat & 0x02)) {
18957: if(sio[c].irq_enable & 0x08) {
18958: state_changed = true;
18959: }
18960: sio[c].modem_stat |= 0x02;
18961: }
18962: }
18963: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
18964: if(!(sio[c].modem_stat & 0x01)) {
18965: if(sio[c].irq_enable & 0x08) {
18966: state_changed = true;
18967: }
18968: sio[c].modem_stat |= 0x01;
18969: }
18970: }
18971: LeaveCriticalSection(&sio_mt[c].csModemStat);
18972:
18973: if(state_changed) {
18974: sio_update_irq(c);
18975: }
1.1.1.25 root 18976: }
18977: }
18978: sio[c].modem_ctrl = data;
18979: break;
18980: case 7:
18981: sio[c].scratch = data;
18982: break;
18983: }
18984: }
18985:
18986: UINT8 sio_read(int c, UINT32 addr)
18987: {
18988: switch(addr & 7) {
18989: case 0:
18990: if(sio[c].selector & 0x80) {
18991: return(sio[c].divisor.b.l);
18992: } else {
18993: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 18994: UINT8 data = 0;
18995: if(sio[c].recv_buffer != NULL) {
18996: data = sio[c].recv_buffer->read();
18997: }
1.1.1.25 root 18998: // data is not ready
18999: sio[c].line_stat_buf &= ~0x01;
19000: LeaveCriticalSection(&sio_mt[c].csRecvData);
19001:
19002: if(sio[c].irq_enable & 0x01) {
19003: sio_update_irq(c);
19004: }
19005: return(data);
19006: }
19007: case 1:
19008: if(sio[c].selector & 0x80) {
19009: return(sio[c].divisor.b.h);
19010: } else {
19011: return(sio[c].irq_enable);
19012: }
19013: case 2:
19014: return(sio[c].irq_identify);
19015: case 3:
19016: return(sio[c].selector);
19017: case 4:
19018: return(sio[c].modem_ctrl);
19019: case 5:
19020: {
19021: EnterCriticalSection(&sio_mt[c].csLineStat);
19022: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
19023: sio[c].line_stat_err = 0x00;
19024: LeaveCriticalSection(&sio_mt[c].csLineStat);
19025:
19026: bool state_changed = false;
19027:
19028: if((sio[c].line_stat_buf & 0x60) == 0x00) {
19029: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 19030: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 19031: // transmitter holding register will be empty first
19032: if(sio[c].irq_enable & 0x02) {
19033: state_changed = true;
19034: }
19035: sio[c].line_stat_buf |= 0x20;
19036: }
19037: LeaveCriticalSection(&sio_mt[c].csSendData);
19038: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
19039: // transmitter shift register will be empty later
19040: sio[c].line_stat_buf |= 0x40;
19041: }
19042: if(!(sio[c].line_stat_buf & 0x01)) {
19043: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 19044: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 19045: // data is ready
19046: if(sio[c].irq_enable & 0x01) {
19047: state_changed = true;
19048: }
19049: sio[c].line_stat_buf |= 0x01;
19050: }
19051: LeaveCriticalSection(&sio_mt[c].csRecvData);
19052: }
19053: if(state_changed) {
19054: sio_update_irq(c);
19055: }
19056: return(val);
19057: }
19058: case 6:
19059: {
19060: EnterCriticalSection(&sio_mt[c].csModemStat);
19061: UINT8 val = sio[c].modem_stat;
19062: sio[c].modem_stat &= 0xf0;
19063: sio[c].prev_modem_stat = sio[c].modem_stat;
19064: LeaveCriticalSection(&sio_mt[c].csModemStat);
19065:
19066: if(sio[c].modem_ctrl & 0x10) {
19067: // loop-back
19068: val &= 0x0f;
19069: val |= (sio[c].modem_ctrl & 0x0c) << 4;
19070: val |= (sio[c].modem_ctrl & 0x01) << 5;
19071: val |= (sio[c].modem_ctrl & 0x02) << 3;
19072: }
19073: return(val);
19074: }
19075: case 7:
19076: return(sio[c].scratch);
19077: }
19078: return(0xff);
19079: }
19080:
19081: void sio_update(int c)
19082: {
19083: if((sio[c].line_stat_buf & 0x60) == 0x00) {
19084: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 19085: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 19086: // transmitter holding/shift registers will be empty
19087: sio[c].line_stat_buf |= 0x60;
19088: }
19089: LeaveCriticalSection(&sio_mt[c].csSendData);
19090: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
19091: // transmitter shift register will be empty
19092: sio[c].line_stat_buf |= 0x40;
19093: }
19094: if(!(sio[c].line_stat_buf & 0x01)) {
19095: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 19096: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 19097: // data is ready
19098: sio[c].line_stat_buf |= 0x01;
19099: }
19100: LeaveCriticalSection(&sio_mt[c].csRecvData);
19101: }
19102: sio_update_irq(c);
19103: }
19104:
19105: void sio_update_irq(int c)
19106: {
19107: int level = -1;
19108:
19109: if(sio[c].irq_enable & 0x08) {
19110: EnterCriticalSection(&sio_mt[c].csModemStat);
19111: if((sio[c].modem_stat & 0x0f) != 0) {
19112: level = 0;
19113: }
19114: EnterCriticalSection(&sio_mt[c].csModemStat);
19115: }
19116: if(sio[c].irq_enable & 0x02) {
19117: if(sio[c].line_stat_buf & 0x20) {
19118: level = 1;
19119: }
19120: }
19121: if(sio[c].irq_enable & 0x01) {
19122: if(sio[c].line_stat_buf & 0x01) {
19123: level = 2;
19124: }
19125: }
19126: if(sio[c].irq_enable & 0x04) {
19127: EnterCriticalSection(&sio_mt[c].csLineStat);
19128: if(sio[c].line_stat_err != 0) {
19129: level = 3;
19130: }
19131: LeaveCriticalSection(&sio_mt[c].csLineStat);
19132: }
1.1.1.29 root 19133:
19134: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 19135: if(level != -1) {
19136: sio[c].irq_identify = level << 1;
1.1.1.29 root 19137: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 19138: } else {
19139: sio[c].irq_identify = 1;
1.1.1.29 root 19140: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 19141: }
19142: }
19143:
19144: DWORD WINAPI sio_thread(void *lpx)
19145: {
19146: volatile sio_t *p = (sio_t *)lpx;
19147: sio_mt_t *q = &sio_mt[p->channel];
19148:
19149: char name[] = "COM1";
1.1.1.26 root 19150: name[3] = '0' + sio_port_number[p->channel];
19151: HANDLE hComm = NULL;
19152: COMMPROP commProp;
19153: DCB dcb;
19154: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
19155: BYTE bytBuffer[SIO_BUFFER_SIZE];
19156:
19157: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
19158: if(GetCommProperties(hComm, &commProp)) {
19159: dwSettableBaud = commProp.dwSettableBaud;
19160: }
1.1.1.25 root 19161: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 19162: // EscapeCommFunction(hComm, SETRTS);
19163: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 19164:
19165: while(!m_halted) {
19166: // setup comm port
19167: bool comm_state_changed = false;
19168:
19169: EnterCriticalSection(&q->csLineCtrl);
19170: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
19171: p->prev_divisor = p->divisor.w;
19172: p->prev_line_ctrl = p->line_ctrl;
19173: comm_state_changed = true;
19174: }
19175: LeaveCriticalSection(&q->csLineCtrl);
19176:
19177: if(comm_state_changed) {
1.1.1.26 root 19178: if(GetCommState(hComm, &dcb)) {
19179: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
19180: DWORD baud = 115200 / p->prev_divisor;
19181: dcb.BaudRate = 9600; // default
19182:
19183: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
19184: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
19185: // 134.5bps is not supported ???
19186: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
19187: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
19188: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
19189: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
19190: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
19191: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
19192: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
19193: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
19194: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
19195: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
19196: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
19197: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
19198: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
19199:
19200: switch(p->prev_line_ctrl & 0x03) {
19201: case 0x00: dcb.ByteSize = 5; break;
19202: case 0x01: dcb.ByteSize = 6; break;
19203: case 0x02: dcb.ByteSize = 7; break;
19204: case 0x03: dcb.ByteSize = 8; break;
19205: }
19206: switch(p->prev_line_ctrl & 0x04) {
19207: case 0x00: dcb.StopBits = ONESTOPBIT; break;
19208: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
19209: }
19210: switch(p->prev_line_ctrl & 0x38) {
19211: case 0x08: dcb.Parity = ODDPARITY; break;
19212: case 0x18: dcb.Parity = EVENPARITY; break;
19213: case 0x28: dcb.Parity = MARKPARITY; break;
19214: case 0x38: dcb.Parity = SPACEPARITY; break;
19215: default: dcb.Parity = NOPARITY; break;
19216: }
19217: dcb.fBinary = TRUE;
19218: dcb.fParity = (dcb.Parity != NOPARITY);
19219: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
19220: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
19221: dcb.fDsrSensitivity = FALSE;//TRUE;
19222: dcb.fTXContinueOnXoff = TRUE;
19223: dcb.fOutX = dcb.fInX = FALSE;
19224: dcb.fErrorChar = FALSE;
19225: dcb.fNull = FALSE;
19226: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
19227: dcb.fAbortOnError = FALSE;
19228:
19229: SetCommState(hComm, &dcb);
1.1.1.25 root 19230: }
19231:
19232: // check again to apply all comm state changes
19233: Sleep(10);
19234: continue;
19235: }
19236:
19237: // set comm pins
19238: bool change_brk = false;
1.1.1.26 root 19239: // bool change_rts = false;
19240: // bool change_dtr = false;
1.1.1.25 root 19241:
19242: EnterCriticalSection(&q->csModemCtrl);
19243: if(p->prev_set_brk != p->set_brk) {
19244: p->prev_set_brk = p->set_brk;
19245: change_brk = true;
19246: }
1.1.1.26 root 19247: // if(p->prev_set_rts != p->set_rts) {
19248: // p->prev_set_rts = p->set_rts;
19249: // change_rts = true;
19250: // }
19251: // if(p->prev_set_dtr != p->set_dtr) {
19252: // p->prev_set_dtr = p->set_dtr;
19253: // change_dtr = true;
19254: // }
1.1.1.25 root 19255: LeaveCriticalSection(&q->csModemCtrl);
19256:
19257: if(change_brk) {
1.1.1.26 root 19258: static UINT32 clear_time = 0;
19259: if(p->prev_set_brk) {
19260: EscapeCommFunction(hComm, SETBREAK);
19261: clear_time = timeGetTime() + 200;
19262: } else {
19263: // keep break for at least 200msec
19264: UINT32 cur_time = timeGetTime();
19265: if(clear_time > cur_time) {
19266: Sleep(clear_time - cur_time);
19267: }
19268: EscapeCommFunction(hComm, CLRBREAK);
19269: }
1.1.1.25 root 19270: }
1.1.1.26 root 19271: // if(change_rts) {
19272: // if(p->prev_set_rts) {
19273: // EscapeCommFunction(hComm, SETRTS);
19274: // } else {
19275: // EscapeCommFunction(hComm, CLRRTS);
19276: // }
19277: // }
19278: // if(change_dtr) {
19279: // if(p->prev_set_dtr) {
19280: // EscapeCommFunction(hComm, SETDTR);
19281: // } else {
19282: // EscapeCommFunction(hComm, CLRDTR);
19283: // }
19284: // }
1.1.1.25 root 19285:
19286: // get comm pins
19287: DWORD dwModemStat = 0;
19288:
19289: if(GetCommModemStatus(hComm, &dwModemStat)) {
19290: EnterCriticalSection(&q->csModemStat);
19291: if(dwModemStat & MS_RLSD_ON) {
19292: p->modem_stat |= 0x80;
19293: } else {
19294: p->modem_stat &= ~0x80;
19295: }
19296: if(dwModemStat & MS_RING_ON) {
19297: p->modem_stat |= 0x40;
19298: } else {
19299: p->modem_stat &= ~0x40;
19300: }
1.1.1.26 root 19301: // if(dwModemStat & MS_DSR_ON) {
19302: // p->modem_stat |= 0x20;
19303: // } else {
19304: // p->modem_stat &= ~0x20;
19305: // }
19306: // if(dwModemStat & MS_CTS_ON) {
19307: // p->modem_stat |= 0x10;
19308: // } else {
19309: // p->modem_stat &= ~0x10;
19310: // }
1.1.1.25 root 19311: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
19312: p->modem_stat |= 0x08;
19313: }
19314: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
19315: p->modem_stat |= 0x04;
19316: }
1.1.1.26 root 19317: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
19318: // p->modem_stat |= 0x02;
19319: // }
19320: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
19321: // p->modem_stat |= 0x01;
19322: // }
1.1.1.25 root 19323: LeaveCriticalSection(&q->csModemStat);
19324: }
19325:
19326: // send data
19327: DWORD dwSend = 0;
19328:
19329: EnterCriticalSection(&q->csSendData);
1.1.1.32 root 19330: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 19331: bytBuffer[dwSend++] = p->send_buffer->read();
19332: }
19333: LeaveCriticalSection(&q->csSendData);
19334:
19335: if(dwSend != 0) {
19336: DWORD dwWritten = 0;
19337: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
19338: }
19339:
19340: // get line status and recv data
19341: DWORD dwLineStat = 0;
19342: COMSTAT comStat;
19343:
19344: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
19345: EnterCriticalSection(&q->csLineStat);
19346: if(dwLineStat & CE_BREAK) {
19347: p->line_stat_err |= 0x10;
19348: }
19349: if(dwLineStat & CE_FRAME) {
19350: p->line_stat_err |= 0x08;
19351: }
19352: if(dwLineStat & CE_RXPARITY) {
19353: p->line_stat_err |= 0x04;
19354: }
19355: if(dwLineStat & CE_OVERRUN) {
19356: p->line_stat_err |= 0x02;
19357: }
19358: LeaveCriticalSection(&q->csLineStat);
19359:
19360: if(comStat.cbInQue != 0) {
19361: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 19362: DWORD dwRecv = 0;
19363: if(p->recv_buffer != NULL) {
19364: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
19365: }
1.1.1.25 root 19366: LeaveCriticalSection(&q->csRecvData);
19367:
19368: if(dwRecv != 0) {
19369: DWORD dwRead = 0;
19370: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
19371: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 19372: if(p->recv_buffer != NULL) {
19373: for(int i = 0; i < dwRead; i++) {
19374: p->recv_buffer->write(bytBuffer[i]);
19375: }
1.1.1.25 root 19376: }
19377: LeaveCriticalSection(&q->csRecvData);
19378: }
19379: }
19380: }
19381: }
19382: Sleep(10);
19383: }
19384: CloseHandle(hComm);
19385: }
19386: return 0;
19387: }
19388:
1.1.1.8 root 19389: // cmos
19390:
19391: void cmos_init()
19392: {
19393: memset(cmos, 0, sizeof(cmos));
19394: cmos_addr = 0;
1.1 root 19395:
1.1.1.8 root 19396: // from DOSBox
19397: cmos_write(0x0a, 0x26);
19398: cmos_write(0x0b, 0x02);
19399: cmos_write(0x0d, 0x80);
1.1 root 19400: }
19401:
1.1.1.8 root 19402: void cmos_write(int addr, UINT8 val)
1.1 root 19403: {
1.1.1.8 root 19404: cmos[addr & 0x7f] = val;
19405: }
19406:
19407: #define CMOS_GET_TIME() { \
19408: UINT32 cur_sec = timeGetTime() / 1000 ; \
19409: if(prev_sec != cur_sec) { \
19410: GetLocalTime(&time); \
19411: prev_sec = cur_sec; \
19412: } \
1.1 root 19413: }
1.1.1.8 root 19414: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 19415:
1.1.1.8 root 19416: UINT8 cmos_read(int addr)
1.1 root 19417: {
1.1.1.8 root 19418: static SYSTEMTIME time;
19419: static UINT32 prev_sec = 0;
1.1 root 19420:
1.1.1.8 root 19421: switch(addr & 0x7f) {
19422: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
19423: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
19424: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
19425: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
19426: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
19427: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
19428: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
19429: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
19430: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
19431: case 0x15: return((MEMORY_END >> 10) & 0xff);
19432: case 0x16: return((MEMORY_END >> 18) & 0xff);
19433: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
19434: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
19435: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
19436: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
19437: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 19438: }
1.1.1.8 root 19439: return(cmos[addr & 0x7f]);
1.1 root 19440: }
19441:
1.1.1.7 root 19442: // kbd (a20)
19443:
19444: void kbd_init()
19445: {
1.1.1.8 root 19446: kbd_data = kbd_command = 0;
1.1.1.7 root 19447: kbd_status = 0x18;
19448: }
19449:
19450: UINT8 kbd_read_data()
19451: {
1.1.1.8 root 19452: kbd_status &= ~1;
1.1.1.7 root 19453: return(kbd_data);
19454: }
19455:
19456: void kbd_write_data(UINT8 val)
19457: {
19458: switch(kbd_command) {
19459: case 0xd1:
19460: i386_set_a20_line((val >> 1) & 1);
19461: break;
19462: }
19463: kbd_command = 0;
1.1.1.8 root 19464: kbd_status &= ~8;
1.1.1.7 root 19465: }
19466:
19467: UINT8 kbd_read_status()
19468: {
19469: return(kbd_status);
19470: }
19471:
19472: void kbd_write_command(UINT8 val)
19473: {
19474: switch(val) {
19475: case 0xd0:
19476: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 19477: kbd_status |= 1;
1.1.1.7 root 19478: break;
19479: case 0xdd:
19480: i386_set_a20_line(0);
19481: break;
19482: case 0xdf:
19483: i386_set_a20_line(1);
19484: break;
1.1.1.26 root 19485: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
19486: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 19487: if(!(val & 1)) {
1.1.1.8 root 19488: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 19489: // reset pic
19490: pic_init();
19491: pic[0].irr = pic[1].irr = 0x00;
19492: pic[0].imr = pic[1].imr = 0xff;
19493: }
19494: CPU_RESET_CALL(CPU_MODEL);
1.1.1.40 root 19495: UINT16 address = *(UINT16 *)(mem + 0x467);
19496: UINT16 selector = *(UINT16 *)(mem + 0x469);
19497: i386_jmp_far(selector, address);
1.1.1.7 root 19498: }
19499: i386_set_a20_line((val >> 1) & 1);
19500: break;
19501: }
19502: kbd_command = val;
1.1.1.8 root 19503: kbd_status |= 8;
1.1.1.7 root 19504: }
19505:
1.1.1.9 root 19506: // vga
19507:
19508: UINT8 vga_read_status()
19509: {
19510: // 60hz
19511: static const int period[3] = {16, 17, 17};
19512: static int index = 0;
19513: UINT32 time = timeGetTime() % period[index];
19514:
19515: index = (index + 1) % 3;
1.1.1.14 root 19516: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 19517: }
19518:
1.1 root 19519: // i/o bus
19520:
1.1.1.29 root 19521: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
19522: //#define SW1US_PATCH
19523:
1.1.1.25 root 19524: UINT8 read_io_byte(offs_t addr)
1.1.1.33 root 19525: #ifdef USE_DEBUGGER
1.1.1.25 root 19526: {
1.1.1.33 root 19527: if(now_debugging) {
19528: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
19529: if(in_break_point.table[i].status == 1) {
19530: if(addr == in_break_point.table[i].addr) {
19531: in_break_point.hit = i + 1;
19532: now_suspended = true;
19533: break;
19534: }
19535: }
19536: }
1.1.1.25 root 19537: }
1.1.1.33 root 19538: return(debugger_read_io_byte(addr));
1.1.1.25 root 19539: }
1.1.1.33 root 19540: UINT8 debugger_read_io_byte(offs_t addr)
1.1.1.25 root 19541: #endif
1.1 root 19542: {
1.1.1.33 root 19543: UINT8 val = 0xff;
19544:
1.1 root 19545: switch(addr) {
1.1.1.29 root 19546: #ifdef SW1US_PATCH
19547: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
19548: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
1.1.1.33 root 19549: val = sio_read(0, addr - 1);
19550: break;
1.1.1.29 root 19551: #else
1.1.1.25 root 19552: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
19553: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1.1.1.33 root 19554: val = dma_read(0, addr);
19555: break;
1.1.1.29 root 19556: #endif
1.1.1.25 root 19557: case 0x20: case 0x21:
1.1.1.33 root 19558: val = pic_read(0, addr);
19559: break;
1.1.1.25 root 19560: case 0x40: case 0x41: case 0x42: case 0x43:
1.1.1.33 root 19561: val = pit_read(addr & 0x03);
19562: break;
1.1.1.7 root 19563: case 0x60:
1.1.1.33 root 19564: val = kbd_read_data();
19565: break;
1.1.1.9 root 19566: case 0x61:
1.1.1.33 root 19567: val = system_port;
19568: break;
1.1.1.7 root 19569: case 0x64:
1.1.1.33 root 19570: val = kbd_read_status();
19571: break;
1.1 root 19572: case 0x71:
1.1.1.33 root 19573: val = cmos_read(cmos_addr);
19574: break;
1.1.1.25 root 19575: case 0x81:
1.1.1.33 root 19576: val = dma_page_read(0, 2);
19577: break;
1.1.1.25 root 19578: case 0x82:
1.1.1.33 root 19579: val = dma_page_read(0, 3);
19580: break;
1.1.1.25 root 19581: case 0x83:
1.1.1.33 root 19582: val = dma_page_read(0, 1);
19583: break;
1.1.1.25 root 19584: case 0x87:
1.1.1.33 root 19585: val = dma_page_read(0, 0);
19586: break;
1.1.1.25 root 19587: case 0x89:
1.1.1.33 root 19588: val = dma_page_read(1, 2);
19589: break;
1.1.1.25 root 19590: case 0x8a:
1.1.1.33 root 19591: val = dma_page_read(1, 3);
19592: break;
1.1.1.25 root 19593: case 0x8b:
1.1.1.33 root 19594: val = dma_page_read(1, 1);
19595: break;
1.1.1.25 root 19596: case 0x8f:
1.1.1.33 root 19597: val = dma_page_read(1, 0);
19598: break;
1.1 root 19599: case 0x92:
1.1.1.33 root 19600: val = (m_a20_mask >> 19) & 2;
19601: break;
1.1.1.25 root 19602: case 0xa0: case 0xa1:
1.1.1.33 root 19603: val = pic_read(1, addr);
19604: break;
1.1.1.25 root 19605: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
19606: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.33 root 19607: val = dma_read(1, (addr - 0xc0) >> 1);
19608: break;
1.1.1.37 root 19609: case 0x278: case 0x279: case 0x27a:
19610: val = pio_read(1, addr);
19611: break;
1.1.1.29 root 19612: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
1.1.1.33 root 19613: val = sio_read(3, addr);
19614: break;
1.1.1.25 root 19615: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
1.1.1.33 root 19616: val = sio_read(1, addr);
19617: break;
1.1.1.25 root 19618: case 0x378: case 0x379: case 0x37a:
1.1.1.33 root 19619: val = pio_read(0, addr);
19620: break;
1.1.1.25 root 19621: case 0x3ba: case 0x3da:
1.1.1.33 root 19622: val = vga_read_status();
19623: break;
1.1.1.37 root 19624: case 0x3bc: case 0x3bd: case 0x3be:
19625: val = pio_read(2, addr);
19626: break;
1.1.1.29 root 19627: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
1.1.1.33 root 19628: val = sio_read(2, addr);
19629: break;
1.1.1.25 root 19630: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
1.1.1.33 root 19631: val = sio_read(0, addr);
19632: break;
1.1 root 19633: default:
1.1.1.33 root 19634: // fatalerror("unknown inb %4x\n", addr);
1.1 root 19635: break;
19636: }
1.1.1.33 root 19637: #ifdef ENABLE_DEBUG_IOPORT
19638: if(fp_debug_log != NULL) {
19639: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
19640: }
19641: #endif
19642: return(val);
1.1 root 19643: }
19644:
19645: UINT16 read_io_word(offs_t addr)
19646: {
19647: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
19648: }
19649:
1.1.1.33 root 19650: #ifdef USE_DEBUGGER
19651: UINT16 debugger_read_io_word(offs_t addr)
19652: {
19653: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
19654: }
19655: #endif
19656:
1.1 root 19657: UINT32 read_io_dword(offs_t addr)
19658: {
19659: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
19660: }
19661:
1.1.1.33 root 19662: #ifdef USE_DEBUGGER
19663: UINT32 debugger_read_io_dword(offs_t addr)
19664: {
19665: 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));
19666: }
19667: #endif
19668:
1.1 root 19669: void write_io_byte(offs_t addr, UINT8 val)
1.1.1.33 root 19670: #ifdef USE_DEBUGGER
19671: {
19672: if(now_debugging) {
19673: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
19674: if(out_break_point.table[i].status == 1) {
19675: if(addr == out_break_point.table[i].addr) {
19676: out_break_point.hit = i + 1;
19677: now_suspended = true;
19678: break;
19679: }
19680: }
19681: }
19682: }
19683: debugger_write_io_byte(addr, val);
19684: }
19685: void debugger_write_io_byte(offs_t addr, UINT8 val)
19686: #endif
1.1 root 19687: {
1.1.1.25 root 19688: #ifdef ENABLE_DEBUG_IOPORT
1.1.1.33 root 19689: if(fp_debug_log != NULL) {
1.1.1.43 root 19690: #ifdef USE_SERVICE_THREAD
19691: if(addr != 0xf7)
19692: #endif
1.1.1.33 root 19693: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
1.1.1.25 root 19694: }
19695: #endif
1.1 root 19696: switch(addr) {
1.1.1.29 root 19697: #ifdef SW1US_PATCH
19698: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
19699: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
19700: sio_write(0, addr - 1, val);
19701: break;
19702: #else
1.1.1.25 root 19703: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
19704: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
19705: dma_write(0, addr, val);
19706: break;
1.1.1.29 root 19707: #endif
1.1.1.25 root 19708: case 0x20: case 0x21:
1.1 root 19709: pic_write(0, addr, val);
19710: break;
1.1.1.25 root 19711: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 19712: pit_write(addr & 0x03, val);
19713: break;
1.1.1.7 root 19714: case 0x60:
19715: kbd_write_data(val);
19716: break;
1.1.1.9 root 19717: case 0x61:
19718: if((system_port & 3) != 3 && (val & 3) == 3) {
19719: // beep on
19720: // MessageBeep(-1);
19721: } else if((system_port & 3) == 3 && (val & 3) != 3) {
19722: // beep off
19723: }
19724: system_port = val;
19725: break;
1.1 root 19726: case 0x64:
1.1.1.7 root 19727: kbd_write_command(val);
1.1 root 19728: break;
19729: case 0x70:
19730: cmos_addr = val;
19731: break;
19732: case 0x71:
1.1.1.8 root 19733: cmos_write(cmos_addr, val);
1.1 root 19734: break;
1.1.1.25 root 19735: case 0x81:
19736: dma_page_write(0, 2, val);
19737: case 0x82:
19738: dma_page_write(0, 3, val);
19739: case 0x83:
19740: dma_page_write(0, 1, val);
19741: case 0x87:
19742: dma_page_write(0, 0, val);
19743: case 0x89:
19744: dma_page_write(1, 2, val);
19745: case 0x8a:
19746: dma_page_write(1, 3, val);
19747: case 0x8b:
19748: dma_page_write(1, 1, val);
19749: case 0x8f:
19750: dma_page_write(1, 0, val);
1.1 root 19751: case 0x92:
1.1.1.7 root 19752: i386_set_a20_line((val >> 1) & 1);
1.1 root 19753: break;
1.1.1.25 root 19754: case 0xa0: case 0xa1:
1.1 root 19755: pic_write(1, addr, val);
19756: break;
1.1.1.25 root 19757: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
19758: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 19759: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 19760: break;
1.1.1.35 root 19761: #ifdef USE_SERVICE_THREAD
19762: case 0xf7:
19763: // dummy i/o for BIOS/DOS service
1.1.1.36 root 19764: if(in_service && cursor_moved) {
19765: // update cursor position before service is done
19766: pcbios_update_cursor_position();
19767: cursor_moved = false;
19768: }
1.1.1.35 root 19769: finish_service_loop();
19770: break;
19771: #endif
1.1.1.37 root 19772: case 0x278: case 0x279: case 0x27a:
19773: pio_write(1, addr, val);
19774: break;
1.1.1.29 root 19775: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
19776: sio_write(3, addr, val);
19777: break;
1.1.1.25 root 19778: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
19779: sio_write(1, addr, val);
19780: break;
19781: case 0x378: case 0x379: case 0x37a:
19782: pio_write(0, addr, val);
19783: break;
1.1.1.37 root 19784: case 0x3bc: case 0x3bd: case 0x3be:
19785: pio_write(2, addr, val);
19786: break;
1.1.1.29 root 19787: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
19788: sio_write(2, addr, val);
19789: break;
1.1.1.25 root 19790: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
19791: sio_write(0, addr, val);
19792: break;
1.1 root 19793: default:
1.1.1.33 root 19794: // fatalerror("unknown outb %4x,%2x\n", addr, val);
1.1 root 19795: break;
19796: }
19797: }
19798:
19799: void write_io_word(offs_t addr, UINT16 val)
19800: {
19801: write_io_byte(addr + 0, (val >> 0) & 0xff);
19802: write_io_byte(addr + 1, (val >> 8) & 0xff);
19803: }
19804:
1.1.1.33 root 19805: #ifdef USE_DEBUGGER
19806: void debugger_write_io_word(offs_t addr, UINT16 val)
19807: {
19808: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
19809: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
19810: }
19811: #endif
19812:
1.1 root 19813: void write_io_dword(offs_t addr, UINT32 val)
19814: {
19815: write_io_byte(addr + 0, (val >> 0) & 0xff);
19816: write_io_byte(addr + 1, (val >> 8) & 0xff);
19817: write_io_byte(addr + 2, (val >> 16) & 0xff);
19818: write_io_byte(addr + 3, (val >> 24) & 0xff);
19819: }
1.1.1.33 root 19820:
19821: #ifdef USE_DEBUGGER
19822: void debugger_write_io_dword(offs_t addr, UINT32 val)
19823: {
19824: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
19825: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
19826: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
19827: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
19828: }
19829: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.