|
|
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.35 root 775: #ifdef USE_SERVICE_THREAD
1.1.1.24 root 776: void i386_call_far(UINT16 selector, UINT32 address)
777: {
778: #if defined(HAS_I386)
779: if(PROTECTED_MODE && !V8086_MODE) {
780: i386_protected_mode_call(selector, address, 1, m_operand_size);
781: } else {
782: PUSH16(SREG(CS));
783: PUSH16(m_eip);
784: SREG(CS) = selector;
785: m_performed_intersegment_jump = 1;
786: i386_load_segment_descriptor(CS);
787: m_eip = address;
788: CHANGE_PC(m_eip);
789: }
790: #else
791: UINT16 ip = m_pc - SREG_BASE(CS);
792: UINT16 cs = SREG(CS);
793: #if defined(HAS_I286)
794: i80286_code_descriptor(selector, address, 2);
795: #else
796: SREG(CS) = selector;
797: i386_load_segment_descriptor(CS);
798: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
799: #endif
800: PUSH(cs);
801: PUSH(ip);
802: CHANGE_PC(m_pc);
803: #endif
804: }
1.1.1.35 root 805: #endif
1.1.1.24 root 806:
1.1.1.29 root 807: UINT16 i386_read_stack()
808: {
809: #if defined(HAS_I386)
810: UINT32 ea, new_esp;
811: if( STACK_32BIT ) {
812: new_esp = REG32(ESP) + 2;
813: ea = i386_translate(SS, new_esp - 2, 0);
814: } else {
815: new_esp = REG16(SP) + 2;
816: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
817: }
818: return READ16(ea);
819: #else
820: UINT16 sp = m_regs.w[SP] + 2;
821: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
822: #endif
823: }
824:
1.1 root 825: /* ----------------------------------------------------------------------------
1.1.1.33 root 826: debugger
827: ---------------------------------------------------------------------------- */
828:
829: #ifdef USE_DEBUGGER
830: #define TELNET_BLUE 0x0004 // text color contains blue.
831: #define TELNET_GREEN 0x0002 // text color contains green.
832: #define TELNET_RED 0x0001 // text color contains red.
833: #define TELNET_INTENSITY 0x0008 // text color is intensified.
834:
835: int svr_socket = 0;
836: int cli_socket = 0;
837:
838: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error);
839:
840: void debugger_init()
841: {
842: now_debugging = false;
843: now_going = false;
844: now_suspended = false;
845: force_suspend = false;
846:
847: memset(&break_point, 0, sizeof(break_point_t));
848: memset(&rd_break_point, 0, sizeof(break_point_t));
849: memset(&wr_break_point, 0, sizeof(break_point_t));
850: memset(&in_break_point, 0, sizeof(break_point_t));
851: memset(&out_break_point, 0, sizeof(break_point_t));
852: memset(&int_break_point, 0, sizeof(int_break_point_t));
853: }
854:
855: void telnet_send(char *string)
856: {
857: char buffer[8192], *ptr;
858: strcpy(buffer, string);
859: while((ptr = strstr(buffer, "\n")) != NULL) {
860: char tmp[8192];
861: *ptr = '\0';
862: sprintf(tmp, "%s\033E%s", buffer, ptr + 1);
863: strcpy(buffer, tmp);
864: }
865:
866: int len = strlen(buffer), res;
867: ptr = buffer;
868: while(len > 0) {
869: if((res = send(cli_socket, ptr, len, 0)) > 0) {
870: len -= res;
871: ptr += res;
872: }
873: }
874: }
875:
876: void telnet_command(const char *format, ...)
877: {
878: char buffer[1024];
879: va_list ap;
880: va_start(ap, format);
881: vsprintf(buffer, format, ap);
882: va_end(ap);
883:
884: telnet_send(buffer);
885: }
886:
887: void telnet_printf(const char *format, ...)
888: {
889: char buffer[1024];
890: va_list ap;
891: va_start(ap, format);
892: vsprintf(buffer, format, ap);
893: va_end(ap);
894:
895: if(fp_debugger != NULL) {
896: fprintf(fp_debugger, "%s", buffer);
897: }
898: telnet_send(buffer);
899: }
900:
901: bool telnet_gets(char *str, int n)
902: {
903: char buffer[1024];
904: int ptr = 0;
905:
906: telnet_command("\033[12l"); // local echo on
907: telnet_command("\033[2l"); // key unlock
908:
909: while(!m_halted) {
910: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
911:
912: if(len > 0 && buffer[0] != 0xff) {
913: for(int i = 0; i < len; i++) {
914: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
915: str[ptr] = 0;
916: telnet_command("\033[2h"); // key lock
917: telnet_command("\033[12h"); // local echo off
918: return(!m_halted);
919: } else if(buffer[i] == 0x08) {
920: if(ptr > 0) {
921: telnet_command("\033[0K"); // erase from cursor position
922: ptr--;
923: } else {
924: telnet_command("\033[1C"); // move cursor forward
925: }
926: } else if(ptr < n - 1) {
1.1.1.37 root 927: if(buffer[i] >= 0x20 && buffer[i] <= 0x7e) {
1.1.1.33 root 928: str[ptr++] = buffer[i];
929: }
930: } else {
931: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position
932: }
933: }
934: } else if(len == -1) {
935: if(WSAGetLastError() != WSAEWOULDBLOCK) {
936: return(false);
937: }
938: } else if(len == 0) {
939: return(false);
940: }
941: Sleep(10);
942: }
943: return(!m_halted);
944: }
945:
946: bool telnet_kbhit()
947: {
948: char buffer[1024];
949:
950: if(!m_halted) {
951: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
952:
953: if(len > 0) {
954: for(int i = 0; i < len; i++) {
955: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
956: return(true);
957: }
958: }
959: } else if(len == 0) {
960: return(true); // disconnected
961: }
962: }
963: return(false);
964: }
965:
966: bool telnet_disconnected()
967: {
968: char buffer[1024];
969: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
970:
971: if(len == 0) {
972: return(true);
973: } else if(len == -1) {
974: if(WSAGetLastError() != WSAEWOULDBLOCK) {
975: return(true);
976: }
977: }
978: return(false);
979: }
980:
981: void telnet_set_color(int color)
982: {
983: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7));
984: }
985:
986: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip)
987: {
988: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1));
989: UINT8 ops[16];
990: for(int i = 0; i < 16; i++) {
991: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK);
992: }
993: UINT8 *oprom = ops;
994:
995: #if defined(HAS_I386)
996: if(m_operand_size) {
997: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK);
998: } else
999: #endif
1000: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK);
1001: }
1002:
1003: void debugger_regs_info(char *buffer)
1004: {
1005: #if defined(HAS_I386)
1006: UINT32 flags = get_flags();
1007: #else
1008: UINT32 flags = CompressFlags();
1009: #endif
1010: #if defined(HAS_I386)
1011: if(m_operand_size) {
1012: 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",
1013: 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),
1014: PROTECTED_MODE ? "PE" : "--",
1015: (flags & 0x40000) ? 'A' : '-',
1016: (flags & 0x20000) ? 'V' : '-',
1017: (flags & 0x10000) ? 'R' : '-',
1018: (flags & 0x04000) ? 'N' : '-',
1019: (flags & 0x02000) ? '1' : '0',
1020: (flags & 0x01000) ? '1' : '0',
1021: (flags & 0x00800) ? 'O' : '-',
1022: (flags & 0x00400) ? 'D' : '-',
1023: (flags & 0x00200) ? 'I' : '-',
1024: (flags & 0x00100) ? 'T' : '-',
1025: (flags & 0x00080) ? 'S' : '-',
1026: (flags & 0x00040) ? 'Z' : '-',
1027: (flags & 0x00010) ? 'A' : '-',
1028: (flags & 0x00004) ? 'P' : '-',
1029: (flags & 0x00001) ? 'C' : '-');
1030: } else {
1031: #endif
1032: 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",
1033: 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),
1034: #if defined(HAS_I386)
1035: PROTECTED_MODE ? "PE" : "--",
1036: #else
1037: "--",
1038: #endif
1039: (flags & 0x40000) ? 'A' : '-',
1040: (flags & 0x20000) ? 'V' : '-',
1041: (flags & 0x10000) ? 'R' : '-',
1042: (flags & 0x04000) ? 'N' : '-',
1043: (flags & 0x02000) ? '1' : '0',
1044: (flags & 0x01000) ? '1' : '0',
1045: (flags & 0x00800) ? 'O' : '-',
1046: (flags & 0x00400) ? 'D' : '-',
1047: (flags & 0x00200) ? 'I' : '-',
1048: (flags & 0x00100) ? 'T' : '-',
1049: (flags & 0x00080) ? 'S' : '-',
1050: (flags & 0x00040) ? 'Z' : '-',
1051: (flags & 0x00010) ? 'A' : '-',
1052: (flags & 0x00004) ? 'P' : '-',
1053: (flags & 0x00001) ? 'C' : '-');
1054: #if defined(HAS_I386)
1055: }
1056: #endif
1057: }
1058:
1059: void debugger_process_info(char *buffer)
1060: {
1061: UINT16 psp_seg = current_psp;
1062: process_t *process;
1063: bool check[0x10000] = {0};
1064:
1065: buffer[0] = '\0';
1066:
1067: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) {
1068: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1069: char *file = process->module_path, *s;
1070: char tmp[8192];
1071:
1072: while((s = strstr(file, "\\")) != NULL) {
1073: file = s + 1;
1074: }
1075: 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));
1076: strcat(tmp, buffer);
1077: strcpy(buffer, tmp);
1078:
1079: check[psp_seg] = true;
1080: psp_seg = psp->parent_psp;
1081: }
1082: }
1083:
1084: UINT32 debugger_get_val(const char *str)
1085: {
1086: char tmp[1024];
1087:
1088: if(str == NULL || strlen(str) == 0) {
1089: return(0);
1090: }
1091: strcpy(tmp, str);
1092:
1093: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') {
1094: // ank
1095: return(tmp[1] & 0xff);
1096: } else if(tmp[0] == '%') {
1097: // decimal
1098: return(strtoul(tmp + 1, NULL, 10));
1099: }
1100: return(strtoul(tmp, NULL, 16));
1101: }
1102:
1103: UINT32 debugger_get_seg(const char *str, UINT32 val)
1104: {
1105: char tmp[1024], *s;
1106:
1107: if(str == NULL || strlen(str) == 0) {
1108: return(val);
1109: }
1110: strcpy(tmp, str);
1111:
1112: if((s = strstr(tmp, ":")) != NULL) {
1113: // 0000:0000
1114: *s = '\0';
1115: return(debugger_get_val(tmp));
1116: }
1117: return(val);
1118: }
1119:
1120: UINT32 debugger_get_ofs(const char *str)
1121: {
1122: char tmp[1024], *s;
1123:
1124: if(str == NULL || strlen(str) == 0) {
1125: return(0);
1126: }
1127: strcpy(tmp, str);
1128:
1129: if((s = strstr(tmp, ":")) != NULL) {
1130: // 0000:0000
1131: return(debugger_get_val(s + 1));
1132: }
1133: return(debugger_get_val(tmp));
1134: }
1135:
1136: void debugger_main()
1137: {
1138: telnet_command("\033[20h"); // cr-lf
1139:
1140: force_suspend = true;
1141: now_going = false;
1142: now_debugging = true;
1143: Sleep(100);
1144:
1145: if(!m_halted && !now_suspended) {
1146: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1147: telnet_printf("waiting until cpu is suspended...\n");
1148: }
1149: while(!m_halted && !now_suspended) {
1150: if(telnet_disconnected()) {
1151: break;
1152: }
1153: Sleep(10);
1154: }
1155:
1156: char buffer[8192];
1157:
1158: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1159: debugger_process_info(buffer);
1160: telnet_printf("%s", buffer);
1161: debugger_regs_info(buffer);
1162: telnet_printf("%s", buffer);
1163: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1164: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip);
1165: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1166: debugger_dasm(buffer, SREG(CS), m_eip);
1167: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1168: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1169:
1170: #define MAX_COMMAND_LEN 64
1171:
1172: char command[MAX_COMMAND_LEN + 1];
1173: char prev_command[MAX_COMMAND_LEN + 1] = {0};
1174:
1175: UINT32 data_seg = SREG(DS);
1176: UINT32 data_ofs = 0;
1177: UINT32 dasm_seg = SREG(CS);
1178: UINT32 dasm_ofs = m_eip;
1179:
1180: while(!m_halted) {
1181: telnet_printf("- ");
1182: command[0] = '\0';
1183:
1184: if(fi_debugger != NULL) {
1185: while(command[0] == '\0') {
1186: if(fgets(command, sizeof(command), fi_debugger) == NULL) {
1187: break;
1188: }
1189: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) {
1190: command[strlen(command) - 1] = '\0';
1191: }
1192: }
1193: if(command[0] != '\0') {
1194: telnet_command("%s\n", command);
1195: }
1196: }
1197: if(command[0] == '\0') {
1198: if(!telnet_gets(command, sizeof(command))) {
1199: break;
1200: }
1201: }
1202: if(command[0] == '\0') {
1203: strcpy(command, prev_command);
1204: } else {
1205: strcpy(prev_command, command);
1206: }
1207: if(fp_debugger != NULL) {
1208: fprintf(fp_debugger, "%s\n", command);
1209: }
1210:
1211: if(!m_halted && command[0] != 0) {
1212: char *params[32], *token = NULL;
1213: int num = 0;
1214:
1215: if((token = strtok(command, " ")) != NULL) {
1216: params[num++] = token;
1217: while(num < 32 && (token = strtok(NULL, " ")) != NULL) {
1218: params[num++] = token;
1219: }
1220: }
1221: if(stricmp(params[0], "D") == 0) {
1222: if(num <= 3) {
1223: if(num >= 2) {
1224: data_seg = debugger_get_seg(params[1], data_seg);
1225: data_ofs = debugger_get_ofs(params[1]);
1226: }
1227: UINT32 end_seg = data_seg;
1228: UINT32 end_ofs = data_ofs + 8 * 16 - 1;
1229: if(num == 3) {
1230: end_seg = debugger_get_seg(params[2], data_seg);
1231: end_ofs = debugger_get_ofs(params[2]);
1232: }
1233: UINT64 start_addr = (data_seg << 4) + data_ofs;
1234: UINT64 end_addr = (end_seg << 4) + end_ofs;
1.1.1.37 root 1235: // bool is_sjis = false;
1.1.1.33 root 1236:
1237: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) {
1238: if((addr & 0x0f) == 0) {
1239: if((data_ofs = addr - (data_seg << 4)) > 0xffff) {
1240: data_seg += 0x1000;
1241: data_ofs -= 0x10000;
1242: }
1243: telnet_printf("%06X:%04X ", data_seg, data_ofs);
1244: memset(buffer, 0, sizeof(buffer));
1245: }
1246: if(addr < start_addr || addr > end_addr) {
1247: telnet_printf(" ");
1248: buffer[addr & 0x0f] = ' ';
1249: } else {
1250: UINT8 data = debugger_read_byte(addr & ADDR_MASK);
1251: telnet_printf(" %02X", data);
1.1.1.37 root 1252: // if(is_sjis) {
1.1.1.33 root 1253: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1254: // is_sjis = false;
1.1.1.33 root 1255: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) {
1256: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1257: // is_sjis = true;
1.1.1.33 root 1258: // } else
1259: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) {
1260: buffer[addr & 0x0f] = data;
1261: } else {
1262: buffer[addr & 0x0f] = '.';
1263: }
1264: }
1265: if((addr & 0x0f) == 0x0f) {
1266: telnet_printf(" %s\n", buffer);
1267: }
1268: }
1269: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) {
1270: data_seg += 0x1000;
1271: data_ofs -= 0x10000;
1272: }
1273: prev_command[1] = '\0'; // remove parameters to dump continuously
1274: } else {
1275: telnet_printf("invalid parameter number\n");
1276: }
1277: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) {
1278: if(num >= 3) {
1279: UINT32 seg = debugger_get_seg(params[1], data_seg);
1280: UINT32 ofs = debugger_get_ofs(params[1]);
1281: for(int i = 2, j = 0; i < num; i++, j++) {
1282: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff);
1283: }
1284: } else {
1285: telnet_printf("invalid parameter number\n");
1286: }
1287: } else if(stricmp(params[0], "EW") == 0) {
1288: if(num >= 3) {
1289: UINT32 seg = debugger_get_seg(params[1], data_seg);
1290: UINT32 ofs = debugger_get_ofs(params[1]);
1291: for(int i = 2, j = 0; i < num; i++, j += 2) {
1292: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff);
1293: }
1294: } else {
1295: telnet_printf("invalid parameter number\n");
1296: }
1297: } else if(stricmp(params[0], "ED") == 0) {
1298: if(num >= 3) {
1299: UINT32 seg = debugger_get_seg(params[1], data_seg);
1300: UINT32 ofs = debugger_get_ofs(params[1]);
1301: for(int i = 2, j = 0; i < num; i++, j += 4) {
1302: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]));
1303: }
1304: } else {
1305: telnet_printf("invalid parameter number\n");
1306: }
1307: } else if(stricmp(params[0], "EA") == 0) {
1308: if(num >= 3) {
1309: UINT32 seg = debugger_get_seg(params[1], data_seg);
1310: UINT32 ofs = debugger_get_ofs(params[1]);
1311: strcpy(buffer, prev_command);
1312: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) {
1313: int len = strlen(token);
1314: for(int i = 0; i < len; i++) {
1315: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff);
1316: }
1317: } else {
1318: telnet_printf("invalid parameter\n");
1319: }
1320: } else {
1321: telnet_printf("invalid parameter number\n");
1322: }
1323: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) {
1324: if(num == 2) {
1325: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff);
1326: } else {
1327: telnet_printf("invalid parameter number\n");
1328: }
1329: } else if(stricmp(params[0], "IW") == 0) {
1330: if(num == 2) {
1331: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff);
1332: } else {
1333: telnet_printf("invalid parameter number\n");
1334: }
1335: } else if(stricmp(params[0], "ID") == 0) {
1336: if(num == 2) {
1337: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1])));
1338: } else {
1339: telnet_printf("invalid parameter number\n");
1340: }
1341: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) {
1342: if(num == 3) {
1343: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff);
1344: } else {
1345: telnet_printf("invalid parameter number\n");
1346: }
1347: } else if(stricmp(params[0], "OW") == 0) {
1348: if(num == 3) {
1349: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff);
1350: } else {
1351: telnet_printf("invalid parameter number\n");
1352: }
1353: } else if(stricmp(params[0], "OD") == 0) {
1354: if(num == 3) {
1355: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2]));
1356: } else {
1357: telnet_printf("invalid parameter number\n");
1358: }
1359: } else if(stricmp(params[0], "R") == 0) {
1360: if(num == 1) {
1361: debugger_regs_info(buffer);
1362: telnet_printf("%s", buffer);
1363: } else if(num == 3) {
1364: #if defined(HAS_I386)
1365: if(stricmp(params[1], "EAX") == 0) {
1366: REG32(EAX) = debugger_get_val(params[2]);
1367: } else if(stricmp(params[1], "EBX") == 0) {
1368: REG32(EBX) = debugger_get_val(params[2]);
1369: } else if(stricmp(params[1], "ECX") == 0) {
1370: REG32(ECX) = debugger_get_val(params[2]);
1371: } else if(stricmp(params[1], "EDX") == 0) {
1372: REG32(EDX) = debugger_get_val(params[2]);
1373: } else if(stricmp(params[1], "ESP") == 0) {
1374: REG32(ESP) = debugger_get_val(params[2]);
1375: } else if(stricmp(params[1], "EBP") == 0) {
1376: REG32(EBP) = debugger_get_val(params[2]);
1377: } else if(stricmp(params[1], "ESI") == 0) {
1378: REG32(ESI) = debugger_get_val(params[2]);
1379: } else if(stricmp(params[1], "EDI") == 0) {
1380: REG32(EDI) = debugger_get_val(params[2]);
1381: } else
1382: #endif
1383: if(stricmp(params[1], "AX") == 0) {
1384: REG16(AX) = debugger_get_val(params[2]);
1385: } else if(stricmp(params[1], "BX") == 0) {
1386: REG16(BX) = debugger_get_val(params[2]);
1387: } else if(stricmp(params[1], "CX") == 0) {
1388: REG16(CX) = debugger_get_val(params[2]);
1389: } else if(stricmp(params[1], "DX") == 0) {
1390: REG16(DX) = debugger_get_val(params[2]);
1391: } else if(stricmp(params[1], "SP") == 0) {
1392: REG16(SP) = debugger_get_val(params[2]);
1393: } else if(stricmp(params[1], "BP") == 0) {
1394: REG16(BP) = debugger_get_val(params[2]);
1395: } else if(stricmp(params[1], "SI") == 0) {
1396: REG16(SI) = debugger_get_val(params[2]);
1397: } else if(stricmp(params[1], "DI") == 0) {
1398: REG16(DI) = debugger_get_val(params[2]);
1399: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) {
1400: #if defined(HAS_I386)
1401: if(m_operand_size) {
1402: m_eip = debugger_get_val(params[2]);
1403: } else {
1404: m_eip = debugger_get_val(params[2]) & 0xffff;
1405: }
1406: CHANGE_PC(m_eip);
1407: #else
1408: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK;
1409: CHANGE_PC(m_pc);
1410: #endif
1411: } else if(stricmp(params[1], "AL") == 0) {
1412: REG8(AL) = debugger_get_val(params[2]);
1413: } else if(stricmp(params[1], "AH") == 0) {
1414: REG8(AH) = debugger_get_val(params[2]);
1415: } else if(stricmp(params[1], "BL") == 0) {
1416: REG8(BL) = debugger_get_val(params[2]);
1417: } else if(stricmp(params[1], "BH") == 0) {
1418: REG8(BH) = debugger_get_val(params[2]);
1419: } else if(stricmp(params[1], "CL") == 0) {
1420: REG8(CL) = debugger_get_val(params[2]);
1421: } else if(stricmp(params[1], "CH") == 0) {
1422: REG8(CH) = debugger_get_val(params[2]);
1423: } else if(stricmp(params[1], "DL") == 0) {
1424: REG8(DL) = debugger_get_val(params[2]);
1425: } else if(stricmp(params[1], "DH") == 0) {
1426: REG8(DH) = debugger_get_val(params[2]);
1427: } else {
1428: telnet_printf("unknown register %s\n", params[1]);
1429: }
1430: } else {
1431: telnet_printf("invalid parameter number\n");
1432: }
1433: } else if(_tcsicmp(params[0], "S") == 0) {
1434: if(num >= 4) {
1435: UINT32 cur_seg = debugger_get_seg(params[1], data_seg);
1436: UINT32 cur_ofs = debugger_get_ofs(params[1]);
1437: UINT32 end_seg = debugger_get_seg(params[2], cur_seg);
1438: UINT32 end_ofs = debugger_get_ofs(params[2]);
1439: UINT8 list[32];
1440:
1441: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1442: list[j] = debugger_get_val(params[i]);
1443: }
1444: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) {
1445: bool found = true;
1446: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1447: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) {
1448: found = false;
1449: break;
1450: }
1451: }
1452: if(found) {
1453: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs);
1454: }
1455: if((cur_ofs += 1) > 0xffff) {
1456: cur_seg += 0x1000;
1457: cur_ofs -= 0x10000;
1458: }
1459: }
1460: } else {
1461: telnet_printf("invalid parameter number\n");
1462: }
1463: } else if(stricmp(params[0], "U") == 0) {
1464: if(num <= 3) {
1465: if(num >= 2) {
1466: dasm_seg = debugger_get_seg(params[1], dasm_seg);
1467: dasm_ofs = debugger_get_ofs(params[1]);
1468: }
1469: if(num == 3) {
1470: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg);
1471: UINT32 end_ofs = debugger_get_ofs(params[2]);
1472:
1473: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) {
1474: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1475: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1476: for(int i = 0; i < len; i++) {
1477: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1478: }
1479: for(int i = len; i < 8; i++) {
1480: telnet_printf(" ");
1481: }
1482: telnet_printf(" %s\n", buffer);
1483: if((dasm_ofs += len) > 0xffff) {
1484: dasm_seg += 0x1000;
1485: dasm_ofs -= 0x10000;
1486: }
1487: }
1488: } else {
1489: for(int i = 0; i < 16; i++) {
1490: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1491: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1492: for(int i = 0; i < len; i++) {
1493: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1494: }
1495: for(int i = len; i < 8; i++) {
1496: telnet_printf(" ");
1497: }
1498: telnet_printf(" %s\n", buffer);
1499: if((dasm_ofs += len) > 0xffff) {
1500: dasm_seg += 0x1000;
1501: dasm_ofs -= 0x10000;
1502: }
1503: }
1504: }
1505: prev_command[1] = '\0'; // remove parameters to disassemble continuously
1506: } else {
1507: telnet_printf("invalid parameter number\n");
1508: }
1509: } else if(stricmp(params[0], "H") == 0) {
1510: if(num == 3) {
1511: UINT32 l = debugger_get_val(params[1]);
1512: UINT32 r = debugger_get_val(params[2]);
1513: telnet_printf("%08X %08X\n", l + r, l - r);
1514: } else {
1515: telnet_printf("invalid parameter number\n");
1516: }
1517: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) {
1518: break_point_t *break_point_ptr;
1519: #define GET_BREAK_POINT_PTR() { \
1520: if(params[0][0] == 'R') { \
1521: break_point_ptr = &rd_break_point; \
1522: } else if(params[0][0] == 'W') { \
1523: break_point_ptr = &wr_break_point; \
1524: } else if(params[0][0] == 'I') { \
1525: break_point_ptr = &in_break_point; \
1526: } else if(params[0][0] == 'O') { \
1527: break_point_ptr = &out_break_point; \
1528: } else { \
1529: break_point_ptr = &break_point; \
1530: } \
1531: }
1532: GET_BREAK_POINT_PTR();
1533: if(num == 2) {
1534: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1535: UINT32 ofs = debugger_get_ofs(params[1]);
1536: bool found = false;
1537: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1538: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) {
1539: break_point_ptr->table[i].addr = (seg << 4) + ofs;
1540: break_point_ptr->table[i].seg = seg;
1541: break_point_ptr->table[i].ofs = ofs;
1542: break_point_ptr->table[i].status = 1;
1543: found = true;
1544: }
1545: }
1546: if(!found) {
1547: telnet_printf("too many break points\n");
1548: }
1549: } else {
1550: telnet_printf("invalid parameter number\n");
1551: }
1552: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) {
1553: break_point_t *break_point_ptr;
1554: GET_BREAK_POINT_PTR();
1555: if(num == 2) {
1556: UINT32 addr = debugger_get_val(params[1]);
1557: bool found = false;
1558: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1559: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) {
1560: break_point_ptr->table[i].addr = addr;
1561: break_point_ptr->table[i].status = 1;
1562: found = true;
1563: }
1564: }
1565: if(!found) {
1566: telnet_printf("too many break points\n");
1567: }
1568: } else {
1569: telnet_printf("invalid parameter number\n");
1570: }
1571: } 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) {
1572: break_point_t *break_point_ptr;
1573: GET_BREAK_POINT_PTR();
1574: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1575: memset(break_point_ptr, 0, sizeof(break_point_t));
1576: } else if(num >= 2) {
1577: for(int i = 1; i < num; i++) {
1578: int index = debugger_get_val(params[i]);
1579: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1580: telnet_printf("invalid index %x\n", index);
1581: } else {
1582: break_point_ptr->table[index - 1].addr = 0;
1583: break_point_ptr->table[index - 1].seg = 0;
1584: break_point_ptr->table[index - 1].ofs = 0;
1585: break_point_ptr->table[index - 1].status = 0;
1586: }
1587: }
1588: } else {
1589: telnet_printf("invalid parameter number\n");
1590: }
1591: } 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 ||
1592: 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) {
1593: break_point_t *break_point_ptr;
1594: GET_BREAK_POINT_PTR();
1595: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1596: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1597: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1598: if(break_point_ptr->table[i].status != 0) {
1599: break_point_ptr->table[i].status = enabled ? 1 : -1;
1600: }
1601: }
1602: } else if(num >= 2) {
1603: for(int i = 1; i < num; i++) {
1604: int index = debugger_get_val(params[i]);
1605: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1606: telnet_printf("invalid index %x\n", index);
1607: } else if(break_point_ptr->table[index - 1].status == 0) {
1608: telnet_printf("break point %x is null\n", index);
1609: } else {
1610: break_point_ptr->table[index - 1].status = enabled ? 1 : -1;
1611: }
1612: }
1613: } else {
1614: telnet_printf("invalid parameter number\n");
1615: }
1616: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) {
1617: break_point_t *break_point_ptr;
1618: GET_BREAK_POINT_PTR();
1619: if(num == 1) {
1620: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1621: if(break_point_ptr->table[i].status) {
1622: 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);
1623: }
1624: }
1625: } else {
1626: telnet_printf("invalid parameter number\n");
1627: }
1628: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) {
1629: break_point_t *break_point_ptr;
1630: GET_BREAK_POINT_PTR();
1631: if(num == 1) {
1632: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1633: if(break_point_ptr->table[i].status) {
1634: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr);
1635: }
1636: }
1637: } else {
1638: telnet_printf("invalid parameter number\n");
1639: }
1640: } else if(stricmp(params[0], "INTBP") == 0) {
1641: if(num >= 2 && num <= 4) {
1642: int int_num = debugger_get_val(params[1]);
1643: UINT8 ah = 0, ah_registered = 0;
1644: UINT8 al = 0, al_registered = 0;
1645: if(num >= 3) {
1646: ah = debugger_get_val(params[2]);
1647: ah_registered = 1;
1648: }
1649: if(num == 4) {
1650: al = debugger_get_val(params[3]);
1651: al_registered = 1;
1652: }
1653: bool found = false;
1654: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1655: if(int_break_point.table[i].status == 0 || (
1656: int_break_point.table[i].int_num == int_num &&
1657: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered &&
1658: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) {
1659: int_break_point.table[i].int_num = int_num;
1660: int_break_point.table[i].ah = ah;
1661: int_break_point.table[i].ah_registered = ah_registered;
1662: int_break_point.table[i].al = al;
1663: int_break_point.table[i].al_registered = al_registered;
1664: int_break_point.table[i].status = 1;
1665: found = true;
1666: }
1667: }
1668: if(!found) {
1669: telnet_printf("too many break points\n");
1670: }
1671: } else {
1672: telnet_printf("invalid parameter number\n");
1673: }
1674: } else if(stricmp(params[0], "INTBC") == 0) {
1675: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1676: memset(&int_break_point, 0, sizeof(int_break_point_t));
1677: } else if(num >= 2) {
1678: for(int i = 1; i < num; i++) {
1679: int index = debugger_get_val(params[i]);
1680: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1681: telnet_printf("invalid index %x\n", index);
1682: } else {
1683: int_break_point.table[index - 1].int_num = 0;
1684: int_break_point.table[index - 1].ah = 0;
1685: int_break_point.table[index - 1].ah_registered = 0;
1686: int_break_point.table[index - 1].al = 0;
1687: int_break_point.table[index - 1].al_registered = 0;
1688: int_break_point.table[index - 1].status = 0;
1689: }
1690: }
1691: } else {
1692: telnet_printf("invalid parameter number\n");
1693: }
1694: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) {
1695: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1696: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1697: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1698: if(int_break_point.table[i].status != 0) {
1699: int_break_point.table[i].status = enabled ? 1 : -1;
1700: }
1701: }
1702: } else if(num >= 2) {
1703: for(int i = 1; i < num; i++) {
1704: int index = debugger_get_val(params[i]);
1705: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1706: telnet_printf("invalid index %x\n", index);
1707: } else if(int_break_point.table[index - 1].status == 0) {
1708: telnet_printf("break point %x is null\n", index);
1709: } else {
1710: int_break_point.table[index - 1].status = enabled ? 1 : -1;
1711: }
1712: }
1713: } else {
1714: telnet_printf("invalid parameter number\n");
1715: }
1716: } else if(stricmp(params[0], "INTBL") == 0) {
1717: if(num == 1) {
1718: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1719: if(int_break_point.table[i].status) {
1720: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num);
1721: if(int_break_point.table[i].ah_registered) {
1722: telnet_printf(" %02X", int_break_point.table[i].ah);
1723: }
1724: if(int_break_point.table[i].al_registered) {
1725: telnet_printf(" %02X", int_break_point.table[i].al);
1726: }
1727: telnet_printf("\n");
1728: }
1729: }
1730: } else {
1731: telnet_printf("invalid parameter number\n");
1732: }
1733: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) {
1734: if(num == 1 || num == 2) {
1735: break_point_t break_point_stored;
1736: bool break_points_stored = false;
1737:
1738: if(stricmp(params[0], "P") == 0) {
1739: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1740: memset(&break_point, 0, sizeof(break_point_t));
1741: break_points_stored = true;
1742:
1743: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip);
1744: break_point.table[0].status = 1;
1745: } else if(num >= 2) {
1746: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1747: memset(&break_point, 0, sizeof(break_point_t));
1748: break_points_stored = true;
1749:
1750: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1751: UINT32 ofs = debugger_get_ofs(params[1]);
1752: break_point.table[0].addr = (seg << 4) + ofs;
1753: break_point.table[0].seg = seg;
1754: break_point.table[0].ofs = ofs;
1755: break_point.table[0].status = 1;
1756: }
1757: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1758: now_going = true;
1759: now_suspended = false;
1760:
1761: telnet_command("\033[2l"); // key unlock
1762: while(!m_halted && !now_suspended) {
1763: if(telnet_kbhit()) {
1764: break;
1765: }
1766: Sleep(10);
1767: }
1768: now_going = false;
1769: telnet_command("\033[2h"); // key lock
1770:
1771: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1772: Sleep(100);
1773: if(!m_halted && !now_suspended) {
1774: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1775: telnet_printf("waiting until cpu is suspended...\n");
1776: }
1777: }
1778: while(!m_halted && !now_suspended) {
1779: if(telnet_disconnected()) {
1780: break;
1781: }
1782: Sleep(10);
1783: }
1784: dasm_seg = SREG(CS);
1785: dasm_ofs = m_eip;
1786:
1787: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1788: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1789: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1790:
1791: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1792: debugger_regs_info(buffer);
1793: telnet_printf("%s", buffer);
1794:
1795: if(break_point.hit) {
1796: if(stricmp(params[0], "G") == 0 && num == 1) {
1797: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1798: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1799: }
1800: } else if(rd_break_point.hit) {
1801: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1802: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1803: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1804: m_prev_cs, m_prev_eip);
1805: } else if(wr_break_point.hit) {
1806: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1807: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1808: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1809: m_prev_cs, m_prev_eip);
1810: } else if(in_break_point.hit) {
1811: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1812: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1813: in_break_point.table[in_break_point.hit - 1].addr,
1814: m_prev_cs, m_prev_eip);
1815: } else if(out_break_point.hit) {
1816: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1817: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1818: out_break_point.table[out_break_point.hit - 1].addr,
1819: m_prev_cs, m_prev_eip);
1820: } else if(int_break_point.hit) {
1821: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1822: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1823: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1824: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1825: }
1826: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1827: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1828: }
1829: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1830: } else {
1831: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1832: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1833: }
1834: if(break_points_stored) {
1835: memcpy(&break_point, &break_point_stored, sizeof(break_point_t));
1836: }
1837: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1838: debugger_dasm(buffer, SREG(CS), m_eip);
1839: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1840: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1841: } else {
1842: telnet_printf("invalid parameter number\n");
1843: }
1844: } else if(stricmp(params[0], "T") == 0) {
1845: if(num == 1 || num == 2) {
1846: int steps = 1;
1847: if(num >= 2) {
1848: steps = debugger_get_val(params[1]);
1849: }
1850:
1851: telnet_command("\033[2l"); // key unlock
1852: while(steps-- > 0) {
1853: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1854: now_going = false;
1855: now_suspended = false;
1856:
1857: while(!m_halted && !now_suspended) {
1858: if(telnet_disconnected()) {
1859: break;
1860: }
1861: Sleep(10);
1862: }
1863: dasm_seg = SREG(CS);
1864: dasm_ofs = m_eip;
1865:
1866: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1867: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1868: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1869:
1870: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1871: debugger_regs_info(buffer);
1872: telnet_printf("%s", buffer);
1873:
1874: 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()) {
1875: break;
1876: }
1877: }
1878: telnet_command("\033[2h"); // key lock
1879:
1880: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1881: Sleep(100);
1882: if(!m_halted && !now_suspended) {
1883: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1884: telnet_printf("waiting until cpu is suspended...\n");
1885: }
1886: }
1887: while(!m_halted && !now_suspended) {
1888: if(telnet_disconnected()) {
1889: break;
1890: }
1891: Sleep(10);
1892: }
1893: if(break_point.hit) {
1894: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1895: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1896: } else if(rd_break_point.hit) {
1897: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1898: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1899: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1900: m_prev_cs, m_prev_eip);
1901: } else if(wr_break_point.hit) {
1902: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1903: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1904: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1905: m_prev_cs, m_prev_eip);
1906: } else if(in_break_point.hit) {
1907: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1908: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1909: in_break_point.table[in_break_point.hit - 1].addr,
1910: m_prev_cs, m_prev_eip);
1911: } else if(out_break_point.hit) {
1912: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1913: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1914: out_break_point.table[out_break_point.hit - 1].addr,
1915: m_prev_cs, m_prev_eip);
1916: } else if(int_break_point.hit) {
1917: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1918: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1919: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1920: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1921: }
1922: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1923: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1924: }
1925: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1926: } else if(steps > 0) {
1927: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1928: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1929: }
1930: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1931: debugger_dasm(buffer, SREG(CS), m_eip);
1932: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1933: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1934: } else {
1935: telnet_printf("invalid parameter number\n");
1936: }
1937: } else if(stricmp(params[0], "Q") == 0) {
1938: break;
1939: } else if(stricmp(params[0], "X") == 0) {
1940: debugger_process_info(buffer);
1941: telnet_printf("%s", buffer);
1942: } else if(stricmp(params[0], ">") == 0) {
1943: if(num == 2) {
1944: if(fp_debugger != NULL) {
1945: fclose(fp_debugger);
1946: fp_debugger = NULL;
1947: }
1948: fp_debugger = fopen(params[1], "w");
1949: } else {
1950: telnet_printf("invalid parameter number\n");
1951: }
1952: } else if(stricmp(params[0], "<") == 0) {
1953: if(num == 2) {
1954: if(fi_debugger != NULL) {
1955: fclose(fi_debugger);
1956: fi_debugger = NULL;
1957: }
1958: fi_debugger = fopen(params[1], "r");
1959: } else {
1960: telnet_printf("invalid parameter number\n");
1961: }
1962: } else if(stricmp(params[0], "?") == 0) {
1963: telnet_printf("D [<start> [<end>]] - dump memory\n");
1964: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n");
1965: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n");
1966: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n");
1967: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n");
1968:
1969: telnet_printf("R - show registers\n");
1970: telnet_printf("R <reg> <value> - edit register\n");
1971: telnet_printf("S <start> <end> <list> - search\n");
1972: telnet_printf("U [<start> [<end>]] - unassemble\n");
1973:
1974: telnet_printf("H <value> <value> - hexadd\n");
1975:
1976: telnet_printf("BP <address> - set breakpoint\n");
1977: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n");
1978: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n");
1979: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n");
1980: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n");
1981: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n");
1982:
1983: telnet_printf("G - go (press enter key to break)\n");
1984: telnet_printf("G <address> - go and break at address\n");
1985: telnet_printf("P - trace one opcode (step over)\n");
1986: telnet_printf("T [<count>] - trace (step in)\n");
1987: telnet_printf("Q - quit\n");
1988: telnet_printf("X - show dos process info\n");
1989:
1990: telnet_printf("> <filename> - output logfile\n");
1991: telnet_printf("< <filename> - input commands from file\n");
1992:
1993: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n");
1994: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n");
1995: } else {
1996: telnet_printf("unknown command %s\n", params[0]);
1997: }
1998: }
1999: }
2000: if(fp_debugger != NULL) {
2001: fclose(fp_debugger);
2002: fp_debugger = NULL;
2003: }
2004: if(fi_debugger != NULL) {
2005: fclose(fi_debugger);
2006: fi_debugger = NULL;
2007: }
2008: now_debugging = now_going = now_suspended = force_suspend = false;
2009: closesocket(cli_socket);
2010: }
2011:
2012: const char *debugger_get_ttermpro_path()
2013: {
2014: static char path[MAX_PATH] = {0};
2015:
2016: if(getenv("ProgramFiles")) {
2017: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles"));
2018: }
2019: return(path);
2020: }
2021:
2022: const char *debugger_get_ttermpro_x86_path()
2023: {
2024: static char path[MAX_PATH] = {0};
2025:
2026: if(getenv("ProgramFiles(x86)")) {
2027: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)"));
2028: }
2029: return(path);
2030: }
2031:
2032: const char *debugger_get_putty_path()
2033: {
2034: static char path[MAX_PATH] = {0};
2035:
2036: if(getenv("ProgramFiles")) {
2037: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles"));
2038: }
2039: return(path);
2040: }
2041:
2042: const char *debugger_get_putty_x86_path()
2043: {
2044: static char path[MAX_PATH] = {0};
2045:
2046: if(getenv("ProgramFiles(x86)")) {
2047: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)"));
2048: }
2049: return(path);
2050: }
2051:
2052: const char *debugger_get_telnet_path()
2053: {
2054: // NOTE: When you run 32bit version of msdos.exe on Windows x64,
2055: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64.
2056: // But 32bit version of telnet.exe will not be installed in SysWOW64
2057: // and 64bit version of telnet.exe will be installed in System32.
2058: static char path[MAX_PATH] = {0};
2059:
2060: if(getenv("windir") != NULL) {
2061: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir"));
2062: }
2063: return(path);
2064: }
2065:
2066: DWORD WINAPI debugger_thread(LPVOID)
2067: {
2068: WSADATA was_data;
2069: struct sockaddr_in svr_addr;
2070: struct sockaddr_in cli_addr;
2071: int cli_addr_len = sizeof(cli_addr);
2072: int port = 23;
2073: int bind_stat = SOCKET_ERROR;
2074: struct timeval timeout;
2075:
2076: WSAStartup(MAKEWORD(2,0), &was_data);
2077:
2078: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
2079: memset(&svr_addr, 0, sizeof(svr_addr));
2080: svr_addr.sin_family = AF_INET;
2081: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
2082:
2083: while(!m_halted && port < 10000) {
2084: svr_addr.sin_port = htons(port);
2085: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
2086: break;
2087: } else {
2088: port = (port == 23) ? 9000 : (port + 1);
2089: }
2090: }
2091: if(bind_stat == 0) {
2092: timeout.tv_sec = 1;
2093: timeout.tv_usec = 0;
2094: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
2095:
2096: listen(svr_socket, 1);
2097:
2098: char command[MAX_PATH] = {0};
2099: STARTUPINFO si;
2100: PROCESS_INFORMATION pi;
2101:
2102: if(_access(debugger_get_ttermpro_path(), 0) == 0) {
2103: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port);
2104: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) {
2105: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port);
2106: } else if(_access(debugger_get_putty_path(), 0) == 0) {
2107: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port);
2108: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) {
2109: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port);
2110: } else if(_access(debugger_get_telnet_path(), 0) == 0) {
2111: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port);
2112: }
2113: if(command[0] != '\0') {
2114: memset(&si, 0, sizeof(STARTUPINFO));
2115: memset(&pi, 0, sizeof(PROCESS_INFORMATION));
2116: CreateProcess(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
2117: }
2118:
2119: while(!m_halted) {
2120: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
2121: u_long val = 1;
2122: ioctlsocket(cli_socket, FIONBIO, &val);
2123: debugger_main();
2124: }
2125: }
2126: }
2127: }
2128: WSACleanup();
2129: return(0);
2130: }
2131: #endif
2132:
2133: /* ----------------------------------------------------------------------------
1.1 root 2134: main
2135: ---------------------------------------------------------------------------- */
2136:
1.1.1.28 root 2137: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
2138: {
2139: if(dwCtrlType == CTRL_BREAK_EVENT) {
1.1.1.33 root 2140: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 2141: #ifdef USE_SERVICE_THREAD
2142: EnterCriticalSection(&key_buf_crit_sect);
2143: #endif
1.1.1.33 root 2144: key_buf_char->clear();
2145: key_buf_scan->clear();
1.1.1.35 root 2146: #ifdef USE_SERVICE_THREAD
2147: LeaveCriticalSection(&key_buf_crit_sect);
2148: #endif
1.1.1.33 root 2149: }
2150: // key_code = key_recv = 0;
1.1.1.28 root 2151: return TRUE;
2152: } else if(dwCtrlType == CTRL_C_EVENT) {
2153: return TRUE;
2154: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
2155: // this program will be terminated abnormally, do minimum end process
2156: exit_handler();
2157: exit(1);
2158: }
2159: return FALSE;
2160: }
2161:
2162: void exit_handler()
2163: {
2164: if(temp_file_created) {
2165: DeleteFile(temp_file_path);
2166: temp_file_created = false;
2167: }
2168: if(key_buf_char != NULL) {
2169: key_buf_char->release();
2170: delete key_buf_char;
2171: key_buf_char = NULL;
2172: }
2173: if(key_buf_scan != NULL) {
2174: key_buf_scan->release();
2175: delete key_buf_scan;
2176: key_buf_scan = NULL;
2177: }
1.1.1.32 root 2178: #ifdef SUPPORT_XMS
2179: msdos_xms_release();
2180: #endif
1.1.1.28 root 2181: hardware_release();
2182: }
2183:
1.1.1.35 root 2184: #ifdef USE_VRAM_THREAD
1.1.1.28 root 2185: DWORD WINAPI vram_thread(LPVOID)
2186: {
2187: while(!m_halted) {
2188: EnterCriticalSection(&vram_crit_sect);
2189: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
2190: vram_flush_char();
2191: }
2192: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
2193: vram_flush_attr();
2194: }
2195: vram_last_length_char = vram_length_char;
2196: vram_last_length_attr = vram_length_attr;
2197: LeaveCriticalSection(&vram_crit_sect);
2198: // this is about half the maximum keyboard repeat rate - any
2199: // lower tends to be jerky, any higher misses updates
2200: Sleep(15);
2201: }
2202: return 0;
2203: }
2204: #endif
2205:
2206: long get_section_in_exec_file(FILE *fp, char *name)
2207: {
2208: UINT8 header[0x400];
2209:
2210: long position = ftell(fp);
2211: fseek(fp, 0, SEEK_SET);
2212: fread(header, sizeof(header), 1, fp);
2213: fseek(fp, position, SEEK_SET);
2214:
2215: try {
2216: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2217: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2218: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2219: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2220: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2221: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2222:
2223: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
2224: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
2225: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
2226: return(sectionHeader->PointerToRawData);
2227: }
2228: }
2229: } catch(...) {
2230: }
2231: return(0);
2232: }
2233:
1.1.1.10 root 2234: bool is_started_from_command_prompt()
2235: {
1.1.1.18 root 2236: bool ret = false;
2237:
2238: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
2239: if(hLibrary) {
2240: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
2241: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
2242: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
2243: if(lpfnGetConsoleProcessList) {
2244: DWORD pl;
2245: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
2246: FreeLibrary(hLibrary);
2247: return(ret);
2248: }
2249: FreeLibrary(hLibrary);
2250: }
2251:
2252: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2253: if(hSnapshot != INVALID_HANDLE_VALUE) {
2254: DWORD dwParentProcessID = 0;
2255: PROCESSENTRY32 pe32;
2256: pe32.dwSize = sizeof(PROCESSENTRY32);
2257: if(Process32First(hSnapshot, &pe32)) {
2258: do {
2259: if(pe32.th32ProcessID == GetCurrentProcessId()) {
2260: dwParentProcessID = pe32.th32ParentProcessID;
2261: break;
2262: }
2263: } while(Process32Next(hSnapshot, &pe32));
2264: }
2265: CloseHandle(hSnapshot);
2266: if(dwParentProcessID != 0) {
2267: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
2268: if(hProcess != NULL) {
2269: HMODULE hMod;
2270: DWORD cbNeeded;
2271: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
2272: char module_name[MAX_PATH];
2273: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
2274: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
2275: }
2276: }
2277: CloseHandle(hProcess);
2278: }
2279: }
2280: }
2281: return(ret);
1.1.1.14 root 2282: }
2283:
2284: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
2285: {
1.1.1.24 root 2286: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 2287: OSVERSIONINFOEX osvi;
2288: DWORDLONG dwlConditionMask = 0;
2289: int op = VER_GREATER_EQUAL;
2290:
2291: // Initialize the OSVERSIONINFOEX structure.
2292: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
2293: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
2294: osvi.dwMajorVersion = dwMajorVersion;
2295: osvi.dwMinorVersion = dwMinorVersion;
2296: osvi.wServicePackMajor = wServicePackMajor;
2297: osvi.wServicePackMinor = wServicePackMinor;
2298:
2299: // Initialize the condition mask.
2300: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
2301: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
2302: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
2303: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
2304:
2305: // Perform the test.
2306: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
2307: }
2308:
1.1.1.27 root 2309: void get_sio_port_numbers()
2310: {
2311: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
2312: HDEVINFO hDevInfo = 0;
2313: HKEY hKey = 0;
2314: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
2315: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
2316: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
2317: char chData[256];
2318: DWORD dwType = 0;
2319: DWORD dwSize = sizeof(chData);
2320: int port_number = 0;
2321:
2322: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
2323: if(_strnicmp(chData, "COM", 3) == 0) {
2324: port_number = atoi(chData + 3);
2325: }
2326: }
2327: RegCloseKey(hKey);
2328:
1.1.1.29 root 2329: 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 2330: continue;
2331: }
2332: if(sio_port_number[0] == 0) {
2333: sio_port_number[0] = port_number;
2334: } else if(sio_port_number[1] == 0) {
2335: sio_port_number[1] = port_number;
1.1.1.29 root 2336: } else if(sio_port_number[2] == 0) {
2337: sio_port_number[2] = port_number;
2338: } else if(sio_port_number[3] == 0) {
2339: sio_port_number[3] = port_number;
1.1.1.27 root 2340: }
1.1.1.29 root 2341: 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 2342: break;
2343: }
2344: }
2345: }
2346: }
2347: }
2348:
1.1.1.28 root 2349: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
2350:
1.1 root 2351: int main(int argc, char *argv[], char *envp[])
2352: {
1.1.1.9 root 2353: int arg_offset = 0;
2354: int standard_env = 0;
1.1.1.14 root 2355: int buf_width = 0, buf_height = 0;
1.1.1.28 root 2356: bool get_console_info_success = false;
2357: bool screen_size_changed = false;
2358:
2359: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
2360: GetModuleFileName(NULL, path, MAX_PATH);
2361: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 2362:
1.1.1.27 root 2363: char dummy_argv_0[] = "msdos.exe";
2364: char dummy_argv_1[MAX_PATH];
2365: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
2366: char new_exec_file[MAX_PATH];
2367: bool convert_cmd_file = false;
1.1.1.28 root 2368: unsigned int code_page = 0;
1.1.1.27 root 2369:
2370: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 2371: // check if command file is embedded to this execution file
2372: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 2373: FILE* fp = fopen(full, "rb");
1.1.1.28 root 2374: long offset = get_section_in_exec_file(fp, ".msdos");
2375: if(offset != 0) {
1.1.1.30 root 2376: UINT8 buffer[16];
1.1.1.28 root 2377: fseek(fp, offset, SEEK_SET);
2378: fread(buffer, sizeof(buffer), 1, fp);
2379:
2380: // restore flags
2381: stay_busy = ((buffer[0] & 0x01) != 0);
2382: no_windows = ((buffer[0] & 0x02) != 0);
2383: standard_env = ((buffer[0] & 0x04) != 0);
2384: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
2385: limit_max_memory = ((buffer[0] & 0x10) != 0);
2386: if((buffer[0] & 0x20) != 0) {
2387: get_sio_port_numbers();
2388: }
2389: if((buffer[0] & 0x40) != 0) {
2390: UMB_TOP = EMS_TOP + EMS_SIZE;
2391: support_ems = true;
1.1.1.30 root 2392: }
1.1.1.27 root 2393: #ifdef SUPPORT_XMS
1.1.1.30 root 2394: if((buffer[0] & 0x80) != 0) {
1.1.1.28 root 2395: support_xms = true;
2396: }
1.1.1.30 root 2397: #endif
1.1.1.28 root 2398: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
2399: buf_width = buffer[1] | (buffer[2] << 8);
2400: buf_height = buffer[3] | (buffer[4] << 8);
2401: }
2402: if(buffer[5] != 0) {
1.1.1.30 root 2403: dos_major_version = buffer[5];
2404: dos_minor_version = buffer[6];
2405: }
2406: if(buffer[7] != 0) {
2407: win_major_version = buffer[7];
2408: win_minor_version = buffer[8];
1.1.1.28 root 2409: }
1.1.1.30 root 2410: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
1.1.1.28 root 2411: SetConsoleCP(code_page);
2412: SetConsoleOutputCP(code_page);
2413: }
1.1.1.30 root 2414: int name_len = buffer[11];
2415: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
1.1.1.28 root 2416:
2417: // restore command file name
2418: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
2419: fread(dummy_argv_1, name_len, 1, fp);
2420:
2421: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
2422: // if original command file exists, create a temporary file name
2423: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
2424: // create a temporary command file in the current director
2425: DeleteFile(dummy_argv_1);
1.1.1.27 root 2426: } else {
1.1.1.28 root 2427: // create a temporary command file in the temporary folder
2428: GetTempPath(MAX_PATH, path);
2429: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
2430: DeleteFile(dummy_argv_1);
2431: } else {
2432: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
2433: }
1.1.1.27 root 2434: }
1.1.1.28 root 2435: // check the command file type
2436: fread(buffer, 2, 1, fp);
2437: fseek(fp, -2, SEEK_CUR);
2438: if(memcmp(buffer, "MZ", 2) != 0) {
2439: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
2440: } else {
2441: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 2442: }
2443: }
1.1.1.28 root 2444:
2445: // restore command file
2446: FILE* fo = fopen(dummy_argv_1, "wb");
2447: for(int i = 0; i < file_len; i++) {
2448: fputc(fgetc(fp), fo);
2449: }
2450: fclose(fo);
2451:
2452: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
2453: temp_file_created = true;
2454: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
2455:
2456: // adjust argc/argv
2457: for(int i = 1; i < argc && (i + 1) < 256; i++) {
2458: dummy_argv[i + 1] = argv[i];
2459: }
2460: argc++;
2461: argv = dummy_argv;
1.1.1.27 root 2462: }
2463: fclose(fp);
2464: }
1.1.1.9 root 2465: for(int i = 1; i < argc; i++) {
1.1.1.25 root 2466: if(_strnicmp(argv[i], "-b", 2) == 0) {
2467: stay_busy = true;
2468: arg_offset++;
1.1.1.27 root 2469: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
2470: if(argv[i][2] != '\0') {
2471: strcpy(new_exec_file, &argv[i][2]);
2472: } else {
2473: strcpy(new_exec_file, "new_exec_file.exe");
2474: }
2475: convert_cmd_file = true;
2476: arg_offset++;
1.1.1.28 root 2477: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
2478: if(IS_NUMERIC(argv[i][2])) {
2479: code_page = atoi(&argv[i][2]);
2480: } else {
2481: code_page = GetConsoleCP();
2482: }
2483: arg_offset++;
1.1.1.25 root 2484: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
2485: no_windows = true;
2486: arg_offset++;
2487: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 2488: standard_env = 1;
2489: arg_offset++;
1.1.1.14 root 2490: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
2491: ignore_illegal_insn = true;
2492: arg_offset++;
2493: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
2494: limit_max_memory = true;
2495: arg_offset++;
2496: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 2497: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
2498: buf_width = buf_height = 0;
2499: }
2500: if(buf_width <= 0 || buf_width > 0x7fff) {
2501: buf_width = 80;
2502: }
2503: if(buf_height <= 0 || buf_height > 0x7fff) {
2504: buf_height = 25;
2505: }
1.1.1.14 root 2506: arg_offset++;
1.1.1.25 root 2507: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 2508: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29 root 2509: char *p0 = &argv[i][2], *p1, *p2, *p3;
2510: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
2511: sio_port_number[1] = atoi(p1 + 1);
2512: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
2513: sio_port_number[2] = atoi(p2 + 1);
2514: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
2515: sio_port_number[3] = atoi(p3 + 1);
2516: }
2517: }
1.1.1.25 root 2518: }
1.1.1.29 root 2519: sio_port_number[0] = atoi(p0);
1.1.1.25 root 2520: }
1.1.1.29 root 2521: 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 2522: get_sio_port_numbers();
1.1.1.25 root 2523: }
2524: arg_offset++;
1.1.1.9 root 2525: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 2526: 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 2527: dos_major_version = argv[i][2] - '0';
2528: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2529: }
2530: arg_offset++;
2531: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
2532: 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]))) {
2533: win_major_version = argv[i][2] - '0';
2534: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 2535: }
2536: arg_offset++;
1.1.1.25 root 2537: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
2538: UMB_TOP = EMS_TOP + EMS_SIZE;
2539: support_ems = true;
2540: #ifdef SUPPORT_XMS
2541: support_xms = true;
2542: #endif
2543: arg_offset++;
1.1.1.9 root 2544: } else {
2545: break;
2546: }
2547: }
2548: if(argc < 2 + arg_offset) {
1.1 root 2549: #ifdef _WIN64
1.1.1.14 root 2550: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 2551: #else
1.1.1.14 root 2552: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 2553: #endif
1.1.1.25 root 2554: fprintf(stderr,
1.1.1.28 root 2555: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.30 root 2556: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
1.1.1.25 root 2557: "\n"
2558: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 2559: #ifdef _WIN64
1.1.1.27 root 2560: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 2561: #else
1.1.1.27 root 2562: "\t-c\tconvert command file to 32bit execution file\n"
2563: #endif
1.1.1.28 root 2564: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 2565: "\t-d\tpretend running under straight DOS, not Windows\n"
2566: "\t-e\tuse a reduced environment block\n"
2567: "\t-i\tignore invalid instructions\n"
2568: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
2569: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
2570: "\t-s\tenable serial I/O and set host's COM port numbers\n"
2571: "\t-v\tset the DOS version\n"
1.1.1.30 root 2572: "\t-w\tset the Windows version\n"
1.1.1.19 root 2573: #ifdef SUPPORT_XMS
1.1.1.28 root 2574: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 2575: #else
1.1.1.28 root 2576: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 2577: #endif
2578: );
1.1.1.10 root 2579:
2580: if(!is_started_from_command_prompt()) {
2581: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
2582: while(!_kbhit()) {
2583: Sleep(10);
2584: }
2585: }
1.1.1.20 root 2586: #ifdef _DEBUG
2587: _CrtDumpMemoryLeaks();
2588: #endif
1.1 root 2589: return(EXIT_FAILURE);
2590: }
1.1.1.27 root 2591: if(convert_cmd_file) {
2592: retval = EXIT_FAILURE;
1.1.1.28 root 2593: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 2594: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 2595: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 2596:
1.1.1.28 root 2597: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
2598: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
2599: } else if((fp = fopen(full, "rb")) == NULL) {
2600: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 2601: } else {
1.1.1.28 root 2602: long offset = get_section_in_exec_file(fp, ".msdos");
2603: if(offset != 0) {
2604: UINT8 buffer[14];
2605: fseek(fp, offset, SEEK_SET);
2606: fread(buffer, sizeof(buffer), 1, fp);
2607: memset(path, 0, sizeof(path));
2608: fread(path, buffer[9], 1, fp);
2609: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
2610: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
2611: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
2612: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
2613: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
2614: } else {
2615: // read pe header of msdos.exe
2616: UINT8 header[0x400];
2617: fseek(fp, 0, SEEK_SET);
2618: fread(header, sizeof(header), 1, fp);
2619:
2620: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2621: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2622: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2623: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2624: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2625: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
2626: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2627:
2628: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
2629: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
2630: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
2631: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
2632: if(dwExtraLastSectionBytes != 0) {
2633: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
2634: dwLastSectionSize += dwRemain;
2635: }
2636: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
2637:
2638: // store msdos.exe
2639: fseek(fp, 0, SEEK_SET);
2640: for(int i = 0; i < dwEndOfFile; i++) {
2641: if((data = fgetc(fp)) != EOF) {
2642: fputc(data, fo);
2643: } else {
2644: // we should not reach here :-(
2645: fputc(0, fo);
2646: }
2647: }
2648:
2649: // store options
2650: UINT8 flags = 0;
2651: if(stay_busy) {
2652: flags |= 0x01;
2653: }
2654: if(no_windows) {
2655: flags |= 0x02;
2656: }
2657: if(standard_env) {
2658: flags |= 0x04;
2659: }
2660: if(ignore_illegal_insn) {
2661: flags |= 0x08;
2662: }
2663: if(limit_max_memory) {
2664: flags |= 0x10;
2665: }
1.1.1.29 root 2666: 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 2667: flags |= 0x20;
2668: }
2669: if(support_ems) {
2670: flags |= 0x40;
2671: }
1.1.1.30 root 2672: #ifdef SUPPORT_XMS
2673: if(support_xms) {
2674: flags |= 0x80;
2675: }
2676: #endif
1.1.1.28 root 2677:
2678: fputc(flags, fo);
2679: fputc((buf_width >> 0) & 0xff, fo);
2680: fputc((buf_width >> 8) & 0xff, fo);
2681: fputc((buf_height >> 0) & 0xff, fo);
2682: fputc((buf_height >> 8) & 0xff, fo);
1.1.1.30 root 2683: fputc(dos_major_version, fo);
2684: fputc(dos_minor_version, fo);
2685: fputc(win_major_version, fo);
2686: fputc(win_minor_version, fo);
1.1.1.28 root 2687: fputc((code_page >> 0) & 0xff, fo);
2688: fputc((code_page >> 8) & 0xff, fo);
2689:
2690: // store command file info
2691: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
2692: int name_len = strlen(name);
2693: fseek(fs, 0, SEEK_END);
2694: long file_size = ftell(fs);
2695:
2696: fputc(name_len, fo);
2697: fputc((file_size >> 0) & 0xff, fo);
2698: fputc((file_size >> 8) & 0xff, fo);
2699: fputc((file_size >> 16) & 0xff, fo);
2700: fputc((file_size >> 24) & 0xff, fo);
2701: fwrite(name, name_len, 1, fo);
2702:
2703: // store command file
2704: fseek(fs, 0, SEEK_SET);
2705: for(int i = 0; i < file_size; i++) {
2706: if((data = fgetc(fs)) != EOF) {
2707: fputc(data, fo);
2708: } else {
2709: // we should not reach here :-(
2710: fputc(0, fo);
2711: }
2712: }
2713:
2714: // store padding data and update pe header
1.1.1.29 root 2715: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
2716: coffHeader->NumberOfSections++;
2717: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
2718: memcpy(newSectionHeader->Name, ".msdos", 6);
2719: newSectionHeader->VirtualAddress = dwVirtualAddress;
2720: newSectionHeader->PointerToRawData = dwEndOfFile;
2721: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 2722: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
2723: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
2724: if(dwExtraRawBytes != 0) {
1.1.1.29 root 2725: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 2726: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
2727: for(int i = 0; i < dwRemain; i++) {
1.1.1.29 root 2728: if(i < 2) {
2729: fputc(padding[i & 15], fo);
2730: } else {
2731: fputc(padding[(i - 2) & 15], fo);
2732: }
1.1.1.28 root 2733: }
2734: newSectionHeader->SizeOfRawData += dwRemain;
2735: }
2736: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
2737:
2738: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
2739: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
2740: if(dwExtraNewSectionBytes != 0) {
2741: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
2742: dwNewSectionSize += dwRemain;
2743: }
2744: optionalHeader->SizeOfImage += dwNewSectionSize;
2745:
2746: fseek(fo, 0, SEEK_SET);
2747: fwrite(header, sizeof(header), 1, fo);
2748:
2749: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
2750: retval = EXIT_SUCCESS;
1.1.1.27 root 2751: }
2752: }
2753: if(fp != NULL) {
2754: fclose(fp);
2755: }
2756: if(fs != NULL) {
2757: fclose(fs);
2758: }
2759: if(fo != NULL) {
2760: fclose(fo);
2761: }
2762: }
2763: #ifdef _DEBUG
2764: _CrtDumpMemoryLeaks();
2765: #endif
2766: return(retval);
2767: }
1.1 root 2768:
1.1.1.14 root 2769: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
2770:
1.1.1.23 root 2771: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2772: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 2773: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 2774:
1.1.1.28 root 2775: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 2776: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 2777: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 2778:
1.1.1.14 root 2779: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
2780: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
2781: SCR_BUF(y,x).Char.AsciiChar = ' ';
2782: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 2783: }
2784: }
1.1.1.28 root 2785: if(get_console_info_success) {
1.1.1.12 root 2786: scr_width = csbi.dwSize.X;
1.1.1.14 root 2787: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2788:
1.1.1.28 root 2789: // v-text shadow buffer size must be lesser than 0x7fd0
2790: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 2791: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
2792: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
2793: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 2794: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 2795: scr_width = 80;
2796: scr_height = 25;
2797: }
1.1.1.28 root 2798: screen_size_changed = true;
1.1.1.14 root 2799: }
1.1.1.12 root 2800: } else {
2801: // for a proof (not a console)
2802: scr_width = 80;
2803: scr_height = 25;
2804: }
1.1.1.14 root 2805: scr_buf_size.X = scr_width;
2806: scr_buf_size.Y = scr_height;
2807: scr_buf_pos.X = scr_buf_pos.Y = 0;
2808: scr_top = csbi.srWindow.Top;
1.1 root 2809: cursor_moved = false;
2810:
1.1.1.35 root 2811: #ifdef USE_SERVICE_THREAD
2812: InitializeCriticalSection(&input_crit_sect);
2813: InitializeCriticalSection(&key_buf_crit_sect);
2814: InitializeCriticalSection(&putch_crit_sect);
2815: #endif
1.1.1.25 root 2816: key_buf_char = new FIFO(256);
2817: key_buf_scan = new FIFO(256);
1.1 root 2818:
2819: hardware_init();
2820:
1.1.1.33 root 2821: #ifdef USE_DEBUGGER
2822: debugger_init();
2823: #endif
2824:
1.1.1.9 root 2825: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 2826: retval = EXIT_FAILURE;
2827: } else {
1.1.1.27 root 2828: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 2829: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
2830: #endif
2831: SetConsoleCtrlHandler(ctrl_handler, TRUE);
2832:
1.1.1.28 root 2833: if(screen_size_changed) {
1.1.1.24 root 2834: change_console_size(scr_width, scr_height);
2835: }
1.1.1.8 root 2836: TIMECAPS caps;
2837: timeGetDevCaps(&caps, sizeof(TIMECAPS));
2838: timeBeginPeriod(caps.wPeriodMin);
1.1.1.35 root 2839: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2840: InitializeCriticalSection(&vram_crit_sect);
2841: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
2842: #endif
1.1.1.33 root 2843: #ifdef USE_DEBUGGER
2844: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL));
2845: // wait until telnet client starts and connects to me
2846: if(_access(debugger_get_ttermpro_path(), 0) == 0 ||
2847: _access(debugger_get_ttermpro_x86_path(), 0) == 0 ||
2848: _access(debugger_get_putty_path(), 0) == 0 ||
2849: _access(debugger_get_putty_x86_path(), 0) == 0 ||
2850: _access(debugger_get_telnet_path(), 0) == 0) {
2851: for(int i = 0; i < 100 && cli_socket == 0; i++) {
2852: Sleep(100);
2853: }
2854: }
2855: #endif
1.1 root 2856: hardware_run();
1.1.1.35 root 2857: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2858: vram_flush();
2859: DeleteCriticalSection(&vram_crit_sect);
2860: #endif
1.1.1.24 root 2861: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 2862:
1.1.1.24 root 2863: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 2864: if(get_console_info_success) {
1.1.1.23 root 2865: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2866: if(restore_console_on_exit) {
1.1.1.14 root 2867: // window can't be bigger than buffer,
2868: // buffer can't be smaller than window,
2869: // so make a tiny window,
2870: // set the required buffer,
2871: // then set the required window
2872: SMALL_RECT rect;
2873: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
2874: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 2875: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 2876: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 2877: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2878: }
1.1.1.14 root 2879: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
2880: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 2881: }
1.1.1.24 root 2882: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
2883:
1.1 root 2884: msdos_finish();
1.1.1.14 root 2885:
2886: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 2887: }
1.1.1.35 root 2888: if(temp_file_created) {
2889: DeleteFile(temp_file_path);
2890: temp_file_created = false;
2891: }
1.1.1.10 root 2892: hardware_finish();
2893:
1.1.1.28 root 2894: if(key_buf_char != NULL) {
2895: key_buf_char->release();
2896: delete key_buf_char;
2897: key_buf_char = NULL;
2898: }
2899: if(key_buf_scan != NULL) {
2900: key_buf_scan->release();
2901: delete key_buf_scan;
2902: key_buf_scan = NULL;
2903: }
1.1.1.35 root 2904: #ifdef USE_SERVICE_THREAD
2905: DeleteCriticalSection(&input_crit_sect);
2906: DeleteCriticalSection(&key_buf_crit_sect);
2907: DeleteCriticalSection(&putch_crit_sect);
2908: #endif
1.1.1.20 root 2909: #ifdef _DEBUG
2910: _CrtDumpMemoryLeaks();
2911: #endif
1.1 root 2912: return(retval);
2913: }
2914:
1.1.1.20 root 2915: /* ----------------------------------------------------------------------------
2916: console
2917: ---------------------------------------------------------------------------- */
2918:
1.1.1.14 root 2919: void change_console_size(int width, int height)
1.1.1.12 root 2920: {
1.1.1.23 root 2921: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2922: CONSOLE_SCREEN_BUFFER_INFO csbi;
2923: SMALL_RECT rect;
2924: COORD co;
2925:
2926: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 2927: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
2928: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
2929: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
2930: SET_RECT(rect, 0, 0, width - 1, height - 1);
2931: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2932: } else if(csbi.dwCursorPosition.Y > height - 1) {
2933: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
2934: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2935: SET_RECT(rect, 0, 0, width - 1, height - 1);
2936: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 2937: }
2938: }
1.1.1.14 root 2939: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 2940: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 2941: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 2942: SetConsoleCursorPosition(hStdout, co);
2943: cursor_moved = true;
2944: }
1.1.1.14 root 2945:
2946: // window can't be bigger than buffer,
2947: // buffer can't be smaller than window,
2948: // so make a tiny window,
2949: // set the required buffer,
2950: // then set the required window
2951: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 2952: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 2953: co.X = width;
2954: co.Y = height;
1.1.1.12 root 2955: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 2956: SET_RECT(rect, 0, 0, width - 1, height - 1);
2957: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2958:
2959: scr_width = scr_buf_size.X = width;
2960: scr_height = scr_buf_size.Y = height;
2961: scr_top = 0;
2962:
2963: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2964:
2965: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 2966: text_vram_end_address = text_vram_top_address + regen;
2967: shadow_buffer_end_address = shadow_buffer_top_address + regen;
2968:
1.1.1.14 root 2969: if(regen > 0x4000) {
2970: regen = 0x8000;
2971: vram_pages = 1;
2972: } else if(regen > 0x2000) {
2973: regen = 0x4000;
2974: vram_pages = 2;
2975: } else if(regen > 0x1000) {
2976: regen = 0x2000;
2977: vram_pages = 4;
2978: } else {
2979: regen = 0x1000;
2980: vram_pages = 8;
2981: }
1.1.1.15 root 2982: *(UINT16 *)(mem + 0x44a) = scr_width;
2983: *(UINT16 *)(mem + 0x44c) = regen;
2984: *(UINT8 *)(mem + 0x484) = scr_height - 1;
2985:
1.1.1.24 root 2986: mouse.min_position.x = 0;
2987: mouse.min_position.y = 0;
1.1.1.34 root 2988: mouse.max_position.x = 8 * (scr_width - 1);
2989: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 2990:
1.1.1.15 root 2991: restore_console_on_exit = true;
1.1.1.14 root 2992: }
2993:
2994: void clear_scr_buffer(WORD attr)
2995: {
2996: for(int y = 0; y < scr_height; y++) {
2997: for(int x = 0; x < scr_width; x++) {
2998: SCR_BUF(y,x).Char.AsciiChar = ' ';
2999: SCR_BUF(y,x).Attributes = attr;
3000: }
3001: }
1.1.1.12 root 3002: }
3003:
1.1.1.24 root 3004: bool update_console_input()
1.1 root 3005: {
1.1.1.35 root 3006: #ifdef USE_SERVICE_THREAD
3007: EnterCriticalSection(&input_crit_sect);
3008: #endif
1.1.1.23 root 3009: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 3010: DWORD dwNumberOfEvents = 0;
1.1 root 3011: DWORD dwRead;
3012: INPUT_RECORD ir[16];
1.1.1.24 root 3013: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
3014: bool result = false;
1.1 root 3015:
1.1.1.8 root 3016: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
3017: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
3018: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 3019: if(ir[i].EventType & MOUSE_EVENT) {
1.1.1.34 root 3020: if(mouse.hidden == 0) {
3021: // NOTE: if restore_console_on_exit, console is not scrolled
3022: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
3023: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
3024: }
3025: // FIXME: character size is always 8x8 ???
3026: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
3027: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
3028:
3029: if(mouse.position.x != x || mouse.position.y != y) {
3030: mouse.position.x = x;
3031: mouse.position.y = y;
3032: mouse.status |= 1;
1.1.1.43! root 3033: mouse.status_alt |= 1;
1.1.1.34 root 3034: }
3035: }
3036: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
3037: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
3038: static const DWORD bits[] = {
3039: FROM_LEFT_1ST_BUTTON_PRESSED, // left
3040: RIGHTMOST_BUTTON_PRESSED, // right
3041: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
3042: };
3043: bool prev_status = mouse.buttons[i].status;
3044: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
3045:
3046: if(!prev_status && mouse.buttons[i].status) {
3047: mouse.buttons[i].pressed_times++;
3048: mouse.buttons[i].pressed_position.x = mouse.position.x;
3049: mouse.buttons[i].pressed_position.y = mouse.position.x;
1.1.1.43! root 3050: if(i < 2) {
! 3051: mouse.status_alt |= 2 << (i * 2);
! 3052: }
1.1.1.34 root 3053: mouse.status |= 2 << (i * 2);
3054: } else if(prev_status && !mouse.buttons[i].status) {
3055: mouse.buttons[i].released_times++;
3056: mouse.buttons[i].released_position.x = mouse.position.x;
3057: mouse.buttons[i].released_position.y = mouse.position.x;
1.1.1.43! root 3058: if(i < 2) {
! 3059: mouse.status_alt |= 4 << (i * 2);
! 3060: }
1.1.1.34 root 3061: mouse.status |= 4 << (i * 2);
1.1.1.14 root 3062: }
3063: }
3064: }
1.1.1.24 root 3065: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.33 root 3066: // update keyboard flags in bios data area
1.1.1.35 root 3067: if(ir[i].Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) {
3068: mem[0x417] |= 0x40;
1.1.1.33 root 3069: } else {
1.1.1.35 root 3070: mem[0x417] &= ~0x40;
1.1.1.33 root 3071: }
1.1.1.35 root 3072: if(ir[i].Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) {
3073: mem[0x417] |= 0x20;
1.1.1.33 root 3074: } else {
1.1.1.35 root 3075: mem[0x417] &= ~0x20;
3076: }
3077: if(ir[i].Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) {
3078: mem[0x417] |= 0x10;
3079: } else {
3080: mem[0x417] &= ~0x10;
1.1.1.33 root 3081: }
3082: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1.1.1.43! root 3083: if(mouse.buttons[0].status || mouse.buttons[1].status) {
! 3084: mouse.status_alt |= 0x80;
! 3085: }
1.1.1.33 root 3086: mem[0x417] |= 0x08;
3087: } else {
3088: mem[0x417] &= ~0x08;
3089: }
1.1.1.35 root 3090: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1.1.1.43! root 3091: if(mouse.buttons[0].status || mouse.buttons[1].status) {
! 3092: mouse.status_alt |= 0x40;
! 3093: }
1.1.1.35 root 3094: mem[0x417] |= 0x04;
1.1.1.33 root 3095: } else {
1.1.1.35 root 3096: mem[0x417] &= ~0x04;
1.1.1.33 root 3097: }
3098: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1.1.1.43! root 3099: if(mouse.buttons[0].status || mouse.buttons[1].status) {
! 3100: mouse.status_alt |= 0x20;
! 3101: }
1.1.1.33 root 3102: if(!(mem[0x417] & 0x03)) {
3103: mem[0x417] |= 0x02; // left shift
3104: }
3105: } else {
3106: mem[0x417] &= ~0x03;
3107: }
1.1.1.35 root 3108: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) {
3109: mem[0x418] |= 0x02;
3110: } else {
3111: mem[0x418] &= ~0x02;
3112: }
3113: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
3114: mem[0x418] |= 0x01;
3115: } else {
3116: mem[0x418] &= ~0x01;
3117: }
1.1.1.33 root 3118:
1.1.1.28 root 3119: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 3120: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.33 root 3121: kbd_status |= 1;
3122:
3123: // update dos key buffer
3124: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
3125: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
3126:
3127: if(ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 3128: // make
1.1.1.24 root 3129: kbd_data &= 0x7f;
3130:
1.1.1.33 root 3131: if(chr == 0x00) {
1.1.1.24 root 3132: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3133: if(scn >= 0x3b && scn <= 0x44) {
3134: scn += 0x68 - 0x3b; // F1 to F10
3135: } else if(scn == 0x57 || scn == 0x58) {
3136: scn += 0x8b - 0x57; // F11 & F12
3137: } else if(scn >= 0x47 && scn <= 0x53) {
3138: scn += 0x97 - 0x47; // edit/arrow clusters
3139: } else if(scn == 0x35) {
3140: scn = 0xa4; // keypad /
3141: }
3142: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3143: if(scn == 0x07) {
3144: chr = 0x1e; // Ctrl+^
3145: } else if(scn == 0x0c) {
3146: chr = 0x1f; // Ctrl+_
3147: } else if(scn >= 0x35 && scn <= 0x58) {
3148: static const UINT8 ctrl_map[] = {
3149: 0x95, // keypad /
3150: 0,
3151: 0x96, // keypad *
3152: 0, 0, 0,
3153: 0x5e, // F1
3154: 0x5f, // F2
3155: 0x60, // F3
3156: 0x61, // F4
3157: 0x62, // F5
3158: 0x63, // F6
3159: 0x64, // F7
3160: 0x65, // F8
3161: 0x66, // F9
3162: 0x67, // F10
3163: 0,
3164: 0,
3165: 0x77, // Home
3166: 0x8d, // Up
3167: 0x84, // PgUp
3168: 0x8e, // keypad -
3169: 0x73, // Left
3170: 0x8f, // keypad center
3171: 0x74, // Right
3172: 0x90, // keyapd +
3173: 0x75, // End
3174: 0x91, // Down
3175: 0x76, // PgDn
3176: 0x92, // Insert
3177: 0x93, // Delete
3178: 0, 0, 0,
3179: 0x89, // F11
3180: 0x8a, // F12
3181: };
3182: scn = ctrl_map[scn - 0x35];
3183: }
3184: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3185: if(scn >= 0x3b && scn <= 0x44) {
3186: scn += 0x54 - 0x3b; // F1 to F10
3187: } else if(scn == 0x57 || scn == 0x58) {
3188: scn += 0x87 - 0x57; // F11 & F12
3189: }
3190: } else if(scn == 0x57 || scn == 0x58) {
3191: scn += 0x85 - 0x57;
3192: }
3193: // ignore shift, ctrl, alt, win and menu keys
3194: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1.1.1.32 root 3195: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3196: #ifdef USE_SERVICE_THREAD
3197: EnterCriticalSection(&key_buf_crit_sect);
3198: #endif
1.1.1.32 root 3199: if(chr == 0) {
3200: key_buf_char->write(0x00);
3201: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
3202: }
3203: key_buf_char->write(chr);
3204: key_buf_scan->write(scn);
1.1.1.35 root 3205: #ifdef USE_SERVICE_THREAD
3206: LeaveCriticalSection(&key_buf_crit_sect);
3207: #endif
1.1.1.24 root 3208: }
3209: }
3210: } else {
3211: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3212: chr = 0;
3213: if(scn >= 0x02 && scn <= 0x0e) {
3214: scn += 0x78 - 0x02; // 1 to 0 - =
3215: }
3216: }
1.1.1.32 root 3217: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3218: #ifdef USE_SERVICE_THREAD
3219: EnterCriticalSection(&key_buf_crit_sect);
3220: #endif
1.1.1.32 root 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.32 root 3226: }
1.1.1.24 root 3227: }
1.1.1.33 root 3228: } else if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) {
3229: // ctrl-break, ctrl-c
3230: if(scn == 0x46) {
3231: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3232: #ifdef USE_SERVICE_THREAD
3233: EnterCriticalSection(&key_buf_crit_sect);
3234: #endif
1.1.1.33 root 3235: key_buf_char->write(0x00);
3236: key_buf_scan->write(0x00);
1.1.1.35 root 3237: #ifdef USE_SERVICE_THREAD
3238: LeaveCriticalSection(&key_buf_crit_sect);
3239: #endif
1.1.1.33 root 3240: }
3241: ctrl_break_pressed = true;
3242: mem[0x471] = 0x80;
3243: raise_int_1bh = true;
3244: } else {
3245: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3246: #ifdef USE_SERVICE_THREAD
3247: EnterCriticalSection(&key_buf_crit_sect);
3248: #endif
1.1.1.33 root 3249: key_buf_char->write(chr);
3250: key_buf_scan->write(scn);
1.1.1.35 root 3251: #ifdef USE_SERVICE_THREAD
3252: LeaveCriticalSection(&key_buf_crit_sect);
3253: #endif
1.1.1.33 root 3254: }
3255: ctrl_c_pressed = (scn == 0x2e);
3256: }
3257: } else {
3258: // break
3259: kbd_data |= 0x80;
1.1 root 3260: }
1.1.1.24 root 3261: result = key_changed = true;
1.1.1.36 root 3262: // IME may be on and it may causes screen scroll up and cursor position change
3263: cursor_moved = true;
1.1 root 3264: }
3265: }
3266: }
3267: }
1.1.1.35 root 3268: #ifdef USE_SERVICE_THREAD
3269: LeaveCriticalSection(&input_crit_sect);
3270: #endif
1.1.1.24 root 3271: return(result);
1.1.1.8 root 3272: }
3273:
1.1.1.14 root 3274: bool update_key_buffer()
1.1.1.8 root 3275: {
1.1.1.35 root 3276: if(update_console_input()) {
3277: return(true);
3278: }
3279: if(key_buf_char != NULL && key_buf_scan != NULL) {
3280: #ifdef USE_SERVICE_THREAD
3281: EnterCriticalSection(&key_buf_crit_sect);
3282: #endif
3283: bool empty = key_buf_char->empty();
3284: #ifdef USE_SERVICE_THREAD
3285: LeaveCriticalSection(&key_buf_crit_sect);
3286: #endif
3287: if(!empty) return(true);
3288: }
3289: return(false);
1.1.1.8 root 3290: }
3291:
1.1.1.20 root 3292: /* ----------------------------------------------------------------------------
3293: MS-DOS virtual machine
3294: ---------------------------------------------------------------------------- */
3295:
1.1.1.32 root 3296: static const struct {
1.1.1.33 root 3297: char *name;
3298: DWORD lcid;
3299: char *std;
3300: char *dlt;
3301: } tz_table[] = {
3302: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
3303: // 0 GMT Greenwich Mean Time GMT0
3304: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
3305: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
3306: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
3307: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
3308: // 2 FST FDT Fernando De Noronha Std FST2FDT
3309: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3310: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3311: // 3 BST Brazil Standard Time BST3
3312: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
3313: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
3314: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
3315: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
3316: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
3317: // 3 GST Greenland Standard Time GST3
3318: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
3319: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
3320: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
3321: // 4 AST ADT Atlantic Standard Time AST4ADT
3322: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
3323: // 4 WST WDT Western Standard (Brazil) WST4WDT
3324: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
3325: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
3326: // 5 EST EDT Eastern Standard Time EST5EDT
3327: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
3328: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
3329: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
3330: // 5 CST CDT Chile Standard Time CST5CDT
3331: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
3332: // 5 AST ADT Acre Standard Time AST5ADT
3333: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
3334: // 5 CST CDT Cuba Standard Time CST5CDT
3335: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
3336: // 6 CST CDT Central Standard Time CST6CDT
3337: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
3338: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
3339: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
3340: // 6 EST EDT Easter Island Standard EST6EDT
3341: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
3342: // 7 MST MDT Mountain Standard Time MST7MDT
3343: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
3344: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
3345: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
3346: // 8 PST PDT Pacific Standard Time PST8PDT
3347: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
3348: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
3349: // 9 AKS AKD Alaska Standard Time AKS9AKD
3350: // 9 YST YDT Yukon Standard Time YST9YST
3351: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
3352: // 10 HST HDT Hawaii Standard Time HST10HDT
3353: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
3354: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
3355: // 11 SST Samoa Standard Time SST11
3356: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
3357: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
3358: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
3359: // -10 GST Guam Standard Time GST-10
3360: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
3361: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
3362: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
3363: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
3364: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
3365: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
3366: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
3367: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
3368: // -9 JST Japan Standard Time JST-9
3369: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
3370: // -9 KST KDT Korean Standard Time KST-9KDT
3371: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
3372: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
3373: // -8 HKT Hong Kong Time HKT-8
3374: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
3375: // -8 CCT China Coast Time CCT-8
3376: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
3377: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
3378: // -8 SST Singapore Standard Time SST-8
3379: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
3380: // -8 WAS WAD Western Australian Standard WAS-8WAD
3381: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
3382: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
3383: // -7:30 JT Java Standard Time JST-7:30
3384: // -7 NST North Sumatra Time NST-7
3385: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
3386: // -5:30 IST Indian Standard Time IST-5:30
3387: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
3388: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
3389: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
3390: // -3 MSK MSD Moscow Winter Time MSK-3MSD
3391: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
3392: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
3393: // -2 EET Eastern Europe Time EET-2
3394: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
3395: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
3396: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
3397: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
3398: // -2 IST IDT Israel Standard Time IST-2IDT
3399: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
3400: // -1 MEZ MES Middle European Time MEZ-1MES
3401: // -1 SWT SST Swedish Winter Time SWT-1SST
3402: // -1 FWT FST French Winter Time FWT-1FST
3403: // -1 CET CES Central European Time CET-1CES
3404: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
3405: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
3406: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
3407: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
3408: // -1 WAT West African Time WAT-1
3409: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
3410: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
3411: // 0 UTC Universal Coordinated Time UTC0
3412: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
3413: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
3414: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
3415: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
3416: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
3417: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
3418: };
3419:
3420: static const struct {
1.1.1.32 root 3421: UINT16 code;
3422: char *message_english;
3423: char *message_japanese;
3424: } standard_error_table[] = {
3425: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3426: {0x02, "File not found", "�t�@�C����������܂���."},
3427: {0x03, "Path not found", "�p�X��������܂���."},
3428: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3429: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3430: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3431: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3432: {0x08, "Insufficient memory", "������������܂���."},
3433: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3434: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3435: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3436: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3437: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3438: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3439: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3440: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3441: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3442: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3443: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3444: {0x15, "Not ready", "�������ł��Ă��܂���."},
3445: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3446: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3447: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3448: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3449: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3450: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3451: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3452: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3453: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3454: {0x1F, "General failure", "�G���[�ł�."},
3455: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3456: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3457: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3458: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3459: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3460: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3461: {0x26, "Out of input", "���͂��I���܂���."},
3462: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3463: /*
3464: {0x32, "Network request not supported", NULL},
3465: {0x33, "Remote computer not listening", NULL},
3466: {0x34, "Duplicate name on network", NULL},
3467: {0x35, "Network name not found", NULL},
3468: {0x36, "Network busy", NULL},
3469: {0x37, "Network device no longer exists", NULL},
3470: {0x38, "Network BIOS command limit exceeded", NULL},
3471: {0x39, "Network adapter hardware error", NULL},
3472: {0x3A, "Incorrect response from network", NULL},
3473: {0x3B, "Unexpected network error", NULL},
3474: {0x3C, "Incompatible remote adapter", NULL},
3475: {0x3D, "Print queue full", NULL},
3476: {0x3E, "Queue not full", NULL},
3477: {0x3F, "Not enough space to print file", NULL},
3478: {0x40, "Network name was deleted", NULL},
3479: {0x41, "Network: Access denied", NULL},
3480: {0x42, "Network device type incorrect", NULL},
3481: {0x43, "Network name not found", NULL},
3482: {0x44, "Network name limit exceeded", NULL},
3483: {0x45, "Network BIOS session limit exceeded", NULL},
3484: {0x46, "Temporarily paused", NULL},
3485: {0x47, "Network request not accepted", NULL},
3486: {0x48, "Network print/disk redirection paused", NULL},
3487: {0x49, "Network software not installed", NULL},
3488: {0x4A, "Unexpected adapter close", NULL},
3489: */
3490: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
1.1.1.33 root 3491: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
1.1.1.32 root 3492: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3493: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3494: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3495: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3496: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3497: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3498: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3499: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
3500: /*
3501: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3502: {0x65, "Not ready", "�������ł��Ă��܂���."},
3503: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3504: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3505: {0x68, "Door open", "���o�[���܂��Ă��܂���."
3506: */
3507: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3508: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3509: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3510: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3511: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3512: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3513: };
3514:
3515: static const struct {
3516: UINT16 code;
3517: char *message_english;
3518: char *message_japanese;
3519: } param_error_table[] = {
3520: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3521: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3522: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3523: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3524: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3525: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3526: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3527: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3528: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3529: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3530: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3531: };
3532:
3533: static const struct {
3534: UINT16 code;
3535: char *message_english;
3536: char *message_japanese;
3537: } critical_error_table[] = {
3538: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3539: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3540: {0x02, "Not ready", "�������ł��Ă��܂���."},
3541: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3542: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3543: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3544: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3545: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3546: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3547: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3548: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3549: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3550: {0x0C, "General failure", "�G���[�ł�."},
3551: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3552: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3553: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3554: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3555: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3556: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3557: {0x13, "Out of input", "���͂��I���܂���."},
3558: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3559: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3560: };
3561:
1.1.1.20 root 3562: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3563: int msdos_psp_get_file_table(int fd, int psp_seg);
3564: void msdos_putch(UINT8 data);
1.1.1.35 root 3565: #ifdef USE_SERVICE_THREAD
3566: void msdos_putch_tmp(UINT8 data);
3567: #endif
1.1.1.20 root 3568:
1.1 root 3569: // process info
3570:
3571: process_t *msdos_process_info_create(UINT16 psp_seg)
3572: {
3573: for(int i = 0; i < MAX_PROCESS; i++) {
3574: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3575: memset(&process[i], 0, sizeof(process_t));
3576: process[i].psp = psp_seg;
3577: return(&process[i]);
3578: }
3579: }
3580: fatalerror("too many processes\n");
3581: return(NULL);
3582: }
3583:
1.1.1.33 root 3584: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error)
1.1 root 3585: {
3586: for(int i = 0; i < MAX_PROCESS; i++) {
3587: if(process[i].psp == psp_seg) {
3588: return(&process[i]);
3589: }
3590: }
1.1.1.33 root 3591: if(show_error) {
3592: fatalerror("invalid psp address\n");
3593: }
1.1 root 3594: return(NULL);
3595: }
3596:
1.1.1.33 root 3597: process_t *msdos_process_info_get(UINT16 psp_seg)
3598: {
3599: return(msdos_process_info_get(psp_seg, true));
3600: }
3601:
1.1.1.23 root 3602: void msdos_sda_update(int psp_seg)
3603: {
3604: sda_t *sda = (sda_t *)(mem + SDA_TOP);
3605:
3606: for(int i = 0; i < MAX_PROCESS; i++) {
3607: if(process[i].psp == psp_seg) {
3608: sda->switchar = process[i].switchar;
3609: sda->current_dta.w.l = process[i].dta.w.l;
3610: sda->current_dta.w.h = process[i].dta.w.h;
3611: sda->current_psp = process[i].psp;
3612: break;
3613: }
3614: }
3615: sda->malloc_strategy = malloc_strategy;
3616: sda->return_code = retval;
3617: sda->current_drive = _getdrive();
3618: }
3619:
1.1.1.13 root 3620: // dta info
3621:
3622: void msdos_dta_info_init()
3623: {
1.1.1.14 root 3624: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 3625: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3626: }
3627: }
3628:
3629: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
3630: {
3631: dtainfo_t *free_dta = NULL;
1.1.1.14 root 3632: for(int i = 0; i < MAX_DTAINFO; i++) {
3633: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
3634: if(free_dta == NULL) {
1.1.1.13 root 3635: free_dta = &dtalist[i];
3636: }
1.1.1.14 root 3637: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 3638: return(&dtalist[i]);
3639: }
3640: }
1.1.1.14 root 3641: if(free_dta) {
1.1.1.13 root 3642: free_dta->psp = psp_seg;
3643: free_dta->dta = dta_laddr;
3644: return(free_dta);
3645: }
3646: fatalerror("too many dta\n");
3647: return(NULL);
3648: }
3649:
3650: void msdos_dta_info_free(UINT16 psp_seg)
3651: {
1.1.1.14 root 3652: for(int i = 0; i < MAX_DTAINFO; i++) {
3653: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 3654: FindClose(dtalist[i].find_handle);
3655: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3656: }
3657: }
3658: }
3659:
1.1 root 3660: void msdos_cds_update(int drv)
3661: {
3662: cds_t *cds = (cds_t *)(mem + CDS_TOP);
3663:
3664: memset(mem + CDS_TOP, 0, CDS_SIZE);
3665: sprintf(cds->path_name, "%c:\\", 'A' + drv);
3666: cds->drive_attrib = 0x4000; // physical drive
3667: cds->physical_drive_number = drv;
3668: }
3669:
1.1.1.17 root 3670: // nls information tables
3671:
3672: // uppercase table (func 6502h)
3673: void msdos_upper_table_update()
3674: {
3675: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3676: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3677: UINT8 c[4];
1.1.1.33 root 3678: *(UINT32 *)c = 0; // reset internal conversion state
3679: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.17 root 3680: c[0] = 0x80 + i;
3681: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
3682: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3683: }
3684: }
3685:
1.1.1.23 root 3686: // lowercase table (func 6503h)
3687: void msdos_lower_table_update()
3688: {
3689: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
3690: for(unsigned i = 0; i < 0x80; ++i) {
3691: UINT8 c[4];
1.1.1.33 root 3692: *(UINT32 *)c = 0; // reset internal conversion state
3693: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.23 root 3694: c[0] = 0x80 + i;
3695: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
3696: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3697: }
3698: }
3699:
1.1.1.17 root 3700: // filename uppercase table (func 6504h)
3701: void msdos_filename_upper_table_init()
3702: {
3703: // depended on (file)system, not on active codepage
3704: // temporary solution: just filling data
3705: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3706: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3707: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
3708: }
3709: }
3710:
3711: // filaname terminator table (func 6505h)
3712: void msdos_filename_terminator_table_init()
3713: {
3714: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
3715: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
3716:
3717: data[2] = 1; // marker? (permissible character value)
3718: data[3] = 0x00; // 00h...FFh
3719: data[4] = 0xff;
3720: data[5] = 0; // marker? (excluded character)
3721: data[6] = 0x00; // 00h...20h
3722: data[7] = 0x20;
3723: data[8] = 2; // marker? (illegal characters for filename)
3724: data[9] = (UINT8)strlen(illegal_chars);
3725: memcpy(data + 10, illegal_chars, data[9]);
3726:
3727: // total length
3728: *(UINT16 *)data = (10 - 2) + data[9];
3729: }
3730:
3731: // collating table (func 6506h)
3732: void msdos_collating_table_update()
3733: {
3734: // temporary solution: just filling data
3735: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 3736: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 3737: mem[COLLATING_TABLE_TOP + 2 + i] = i;
3738: }
3739: }
3740:
1.1 root 3741: // dbcs
3742:
3743: void msdos_dbcs_table_update()
3744: {
3745: UINT8 dbcs_data[DBCS_SIZE];
3746: memset(dbcs_data, 0, sizeof(dbcs_data));
3747:
3748: CPINFO info;
3749: GetCPInfo(active_code_page, &info);
3750:
3751: if(info.MaxCharSize != 1) {
3752: for(int i = 0;; i += 2) {
3753: UINT8 lo = info.LeadByte[i + 0];
3754: UINT8 hi = info.LeadByte[i + 1];
3755: dbcs_data[2 + i + 0] = lo;
3756: dbcs_data[2 + i + 1] = hi;
3757: if(lo == 0 && hi == 0) {
3758: dbcs_data[0] = i + 2;
3759: break;
3760: }
3761: }
3762: } else {
3763: dbcs_data[0] = 2; // ???
3764: }
3765: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
3766: }
3767:
1.1.1.17 root 3768: void msdos_dbcs_table_finish()
3769: {
1.1.1.32 root 3770: if(system_code_page != _getmbcp()) {
1.1.1.17 root 3771: _setmbcp(system_code_page);
3772: }
1.1.1.32 root 3773: if(console_code_page != GetConsoleCP()) {
3774: SetConsoleCP(console_code_page);
3775: SetConsoleOutputCP(console_code_page);
3776: }
1.1.1.17 root 3777: }
3778:
3779: void msdos_nls_tables_init()
1.1 root 3780: {
1.1.1.32 root 3781: active_code_page = console_code_page = GetConsoleCP();
3782: system_code_page = _getmbcp();
3783:
3784: if(active_code_page != system_code_page) {
3785: if(_setmbcp(active_code_page) != 0) {
3786: active_code_page = system_code_page;
3787: }
3788: }
3789:
1.1.1.17 root 3790: msdos_upper_table_update();
1.1.1.23 root 3791: msdos_lower_table_update();
1.1.1.17 root 3792: msdos_filename_terminator_table_init();
3793: msdos_filename_upper_table_init();
3794: msdos_collating_table_update();
1.1 root 3795: msdos_dbcs_table_update();
3796: }
3797:
1.1.1.17 root 3798: void msdos_nls_tables_update()
1.1 root 3799: {
1.1.1.17 root 3800: msdos_dbcs_table_update();
3801: msdos_upper_table_update();
1.1.1.23 root 3802: msdos_lower_table_update();
3803: // msdos_collating_table_update();
1.1 root 3804: }
3805:
3806: int msdos_lead_byte_check(UINT8 code)
3807: {
3808: UINT8 *dbcs_table = mem + DBCS_TABLE;
3809:
3810: for(int i = 0;; i += 2) {
3811: UINT8 lo = dbcs_table[i + 0];
3812: UINT8 hi = dbcs_table[i + 1];
3813: if(lo == 0 && hi == 0) {
3814: break;
3815: }
3816: if(lo <= code && code <= hi) {
3817: return(1);
3818: }
3819: }
3820: return(0);
3821: }
3822:
1.1.1.20 root 3823: int msdos_ctrl_code_check(UINT8 code)
3824: {
1.1.1.22 root 3825: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 3826: }
3827:
1.1.1.36 root 3828: int msdos_kanji_2nd_byte_check(UINT8 *buf, int n)
3829: {
3830: int is_kanji_1st = 0;
3831: int is_kanji_2nd = 0;
3832:
3833: for(int p = 0;; p++) {
3834: if(is_kanji_1st) {
3835: is_kanji_1st = 0;
3836: is_kanji_2nd = 1;
3837: } else if(msdos_lead_byte_check(buf[p])) {
3838: is_kanji_1st = 1;
3839: }
3840: if(p == n) {
3841: return(is_kanji_2nd);
3842: }
3843: is_kanji_2nd = 0;
3844: }
3845: }
3846:
1.1 root 3847: // file control
3848:
1.1.1.14 root 3849: char *msdos_remove_double_quote(char *path)
3850: {
3851: static char tmp[MAX_PATH];
3852:
3853: memset(tmp, 0, sizeof(tmp));
3854: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
3855: memcpy(tmp, path + 1, strlen(path) - 2);
3856: } else {
3857: strcpy(tmp, path);
3858: }
3859: return(tmp);
3860: }
3861:
1.1.1.32 root 3862: char *msdos_remove_end_separator(char *path)
3863: {
3864: static char tmp[MAX_PATH];
3865:
3866: strcpy(tmp, path);
3867: int len = strlen(tmp);
3868: if(len > 3 && tmp[len - 1] == '\\') {
3869: tmp[len - 1] = '\0';
3870: }
3871: return(tmp);
3872: }
3873:
1.1.1.14 root 3874: char *msdos_combine_path(char *dir, const char *file)
3875: {
3876: static char tmp[MAX_PATH];
3877: char *tmp_dir = msdos_remove_double_quote(dir);
3878:
3879: if(strlen(tmp_dir) == 0) {
3880: strcpy(tmp, file);
3881: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
3882: sprintf(tmp, "%s%s", tmp_dir, file);
3883: } else {
3884: sprintf(tmp, "%s\\%s", tmp_dir, file);
3885: }
3886: return(tmp);
3887: }
3888:
1.1 root 3889: char *msdos_trimmed_path(char *path, int lfn)
3890: {
3891: static char tmp[MAX_PATH];
3892:
3893: if(lfn) {
3894: strcpy(tmp, path);
3895: } else {
3896: // remove space in the path
3897: char *src = path, *dst = tmp;
3898:
3899: while(*src != '\0') {
3900: if(msdos_lead_byte_check(*src)) {
3901: *dst++ = *src++;
3902: *dst++ = *src++;
3903: } else if(*src != ' ') {
3904: *dst++ = *src++;
3905: } else {
3906: src++; // skip space
3907: }
3908: }
3909: *dst = '\0';
3910: }
1.1.1.14 root 3911: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
3912: // redirect C:\COMMAND.COM to comspec_path
3913: strcpy(tmp, comspec_path);
3914: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
3915: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
3916: static int root_drive_protected = -1;
3917: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
3918: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
3919:
3920: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
3921: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
3922: strcpy(name, name_temp);
3923: name_temp[0] = '\0';
3924:
3925: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
3926: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
3927: if(root_drive_protected == -1) {
3928: FILE *fp = NULL;
3929:
3930: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
3931: root_drive_protected = 1;
3932: try {
3933: if((fp = fopen(temp, "w")) != NULL) {
3934: if(fprintf(fp, "TEST") == 4) {
3935: root_drive_protected = 0;
3936: }
3937: }
3938: } catch(...) {
3939: }
3940: if(fp != NULL) {
3941: fclose(fp);
3942: }
3943: if(_access(temp, 0) == 0) {
3944: remove(temp);
3945: }
3946: }
3947: if(root_drive_protected == 1) {
3948: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
3949: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
3950: strcpy(tmp, msdos_combine_path(temp, name));
3951: }
3952: }
3953: }
3954: }
3955: }
1.1 root 3956: return(tmp);
3957: }
3958:
1.1.1.28 root 3959: char *msdos_get_multiple_short_path(char *src)
3960: {
1.1.1.32 root 3961: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 3962: static char env_path[ENV_SIZE];
3963: char tmp[ENV_SIZE], *token;
3964:
3965: memset(env_path, 0, sizeof(env_path));
3966: strcpy(tmp, src);
3967: token = my_strtok(tmp, ";");
3968:
3969: while(token != NULL) {
3970: if(token[0] != '\0') {
3971: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.32 root 3972: if(path != NULL && strlen(path) != 0) {
3973: if(env_path[0] != '\0') {
3974: strcat(env_path, ";");
3975: }
1.1.1.28 root 3976: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32 root 3977: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 3978: } else {
3979: my_strupr(short_path);
1.1.1.32 root 3980: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 3981: }
3982: }
3983: }
3984: token = my_strtok(NULL, ";");
3985: }
3986: return(env_path);
3987: }
3988:
1.1 root 3989: bool match(char *text, char *pattern)
3990: {
1.1.1.24 root 3991: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 3992: switch(*pattern) {
1.1 root 3993: case '\0':
3994: return !*text;
3995: case '*':
1.1.1.14 root 3996: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 3997: case '?':
3998: return *text && match(text + 1, pattern + 1);
3999: default:
4000: return (*text == *pattern) && match(text + 1, pattern + 1);
4001: }
4002: }
4003:
4004: bool msdos_match_volume_label(char *path, char *volume)
4005: {
4006: char *p;
4007:
1.1.1.14 root 4008: if(!*volume) {
4009: return false;
4010: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 4011: return msdos_match_volume_label(p + 1, volume);
4012: } else if((p = my_strchr(path, '\\')) != NULL) {
4013: return msdos_match_volume_label(p + 1, volume);
4014: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 4015: char tmp[MAX_PATH];
4016: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
4017: return match(volume, tmp);
1.1 root 4018: } else {
4019: return match(volume, path);
4020: }
4021: }
4022:
4023: char *msdos_fcb_path(fcb_t *fcb)
4024: {
4025: static char tmp[MAX_PATH];
4026: char name[9], ext[4];
4027:
4028: memset(name, 0, sizeof(name));
4029: memcpy(name, fcb->file_name, 8);
4030: strcpy(name, msdos_trimmed_path(name, 0));
4031:
4032: memset(ext, 0, sizeof(ext));
4033: memcpy(ext, fcb->file_name + 8, 3);
4034: strcpy(ext, msdos_trimmed_path(ext, 0));
4035:
4036: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
4037: strcpy(name, "*");
4038: }
4039: if(ext[0] == '\0') {
4040: strcpy(tmp, name);
4041: } else {
4042: if(strcmp(ext, "???") == 0) {
4043: strcpy(ext, "*");
4044: }
4045: sprintf(tmp, "%s.%s", name, ext);
4046: }
4047: return(tmp);
4048: }
4049:
4050: void msdos_set_fcb_path(fcb_t *fcb, char *path)
4051: {
4052: char *ext = my_strchr(path, '.');
4053:
4054: memset(fcb->file_name, 0x20, 8 + 3);
4055: if(ext != NULL && path[0] != '.') {
4056: *ext = '\0';
4057: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
4058: }
4059: memcpy(fcb->file_name, path, strlen(path));
4060: }
4061:
4062: char *msdos_short_path(char *path)
4063: {
4064: static char tmp[MAX_PATH];
4065:
1.1.1.24 root 4066: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
4067: strcpy(tmp, path);
4068: }
1.1 root 4069: my_strupr(tmp);
4070: return(tmp);
4071: }
4072:
1.1.1.13 root 4073: char *msdos_short_name(WIN32_FIND_DATA *fd)
4074: {
4075: static char tmp[MAX_PATH];
4076:
1.1.1.14 root 4077: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4078: strcpy(tmp, fd->cAlternateFileName);
4079: } else {
4080: strcpy(tmp, fd->cFileName);
4081: }
4082: my_strupr(tmp);
4083: return(tmp);
4084: }
4085:
1.1 root 4086: char *msdos_short_full_path(char *path)
4087: {
4088: static char tmp[MAX_PATH];
4089: char full[MAX_PATH], *name;
4090:
1.1.1.14 root 4091: // Full works with non-existent files, but Short does not
1.1 root 4092: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 4093: *tmp = '\0';
4094: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
4095: name[-1] = '\0';
4096: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
4097: if(len == 0) {
4098: strcpy(tmp, full);
4099: } else {
4100: tmp[len++] = '\\';
4101: strcpy(tmp + len, name);
4102: }
4103: }
1.1 root 4104: my_strupr(tmp);
4105: return(tmp);
4106: }
4107:
4108: char *msdos_short_full_dir(char *path)
4109: {
4110: static char tmp[MAX_PATH];
4111: char full[MAX_PATH], *name;
4112:
4113: GetFullPathName(path, MAX_PATH, full, &name);
4114: name[-1] = '\0';
1.1.1.24 root 4115: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
4116: strcpy(tmp, full);
4117: }
1.1 root 4118: my_strupr(tmp);
4119: return(tmp);
4120: }
4121:
4122: char *msdos_local_file_path(char *path, int lfn)
4123: {
4124: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 4125: #if 0
4126: // I have forgotten the reason of this routine... :-(
1.1 root 4127: if(_access(trimmed, 0) != 0) {
4128: process_t *process = msdos_process_info_get(current_psp);
4129: static char tmp[MAX_PATH];
4130:
4131: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
4132: if(_access(tmp, 0) == 0) {
4133: return(tmp);
4134: }
4135: }
1.1.1.14 root 4136: #endif
1.1 root 4137: return(trimmed);
4138: }
4139:
1.1.1.29 root 4140: bool msdos_is_device_path(char *path)
1.1.1.11 root 4141: {
4142: char full[MAX_PATH], *name;
4143:
1.1.1.24 root 4144: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4145: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4146: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4147: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4148: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4149: _stricmp(full, "\\\\.\\COM1") == 0 ||
4150: _stricmp(full, "\\\\.\\COM2") == 0 ||
4151: _stricmp(full, "\\\\.\\COM3") == 0 ||
4152: _stricmp(full, "\\\\.\\COM4") == 0 ||
4153: _stricmp(full, "\\\\.\\COM5") == 0 ||
4154: _stricmp(full, "\\\\.\\COM6") == 0 ||
4155: _stricmp(full, "\\\\.\\COM7") == 0 ||
4156: _stricmp(full, "\\\\.\\COM8") == 0 ||
4157: _stricmp(full, "\\\\.\\COM9") == 0 ||
4158: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4159: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4160: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4161: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4162: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4163: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4164: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4165: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4166: _stricmp(full, "\\\\.\\LPT9") == 0) {
4167: return(true);
4168: } else if(name != NULL) {
4169: if(_stricmp(name, "CLOCK$" ) == 0 ||
4170: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 4171: _stricmp(name, "EMMXXXX0") == 0 ||
1.1.1.43! root 4172: // _stricmp(name, "SCSIMGR$") == 0 ||
1.1.1.30 root 4173: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 4174: return(true);
4175: }
4176: }
1.1.1.24 root 4177: }
4178: return(false);
1.1.1.11 root 4179: }
4180:
1.1.1.29 root 4181: bool msdos_is_con_path(char *path)
1.1.1.8 root 4182: {
1.1.1.14 root 4183: char full[MAX_PATH], *name;
1.1.1.8 root 4184:
1.1.1.24 root 4185: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4186: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 4187: }
4188: return(false);
4189: }
4190:
1.1.1.29 root 4191: int msdos_is_comm_path(char *path)
1.1.1.24 root 4192: {
4193: char full[MAX_PATH], *name;
4194:
4195: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4196: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4197: return(1);
4198: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4199: return(2);
4200: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4201: return(3);
4202: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4203: return(4);
1.1.1.24 root 4204: }
4205: }
1.1.1.29 root 4206: return(0);
4207: }
4208:
1.1.1.37 root 4209: void msdos_set_comm_params(int sio_port, char *path)
4210: {
4211: // COM1:{110,150,300,600,1200,2400,4800,9600},{N,O,E,M,S},{8,7,6,5},{1,1.5,2}
4212: char *p = NULL;
4213:
4214: if((p = strstr(path, ":")) != NULL) {
4215: UINT8 selector = sio_read(sio_port - 1, 3);
4216:
4217: // baud rate
4218: int baud = max(110, min(9600, atoi(p + 1)));
4219: UINT16 divisor = 115200 / baud;
4220:
4221: if((p = strstr(p + 1, ",")) != NULL) {
4222: // parity
4223: if(p[1] == 'N' || p[1] == 'n') {
4224: selector = (selector & ~0x38) | 0x00;
4225: } else if(p[1] == 'O' || p[1] == 'o') {
4226: selector = (selector & ~0x38) | 0x08;
4227: } else if(p[1] == 'E' || p[1] == 'e') {
4228: selector = (selector & ~0x38) | 0x18;
4229: } else if(p[1] == 'M' || p[1] == 'm') {
4230: selector = (selector & ~0x38) | 0x28;
4231: } else if(p[1] == 'S' || p[1] == 's') {
4232: selector = (selector & ~0x38) | 0x38;
4233: }
4234: if((p = strstr(p + 1, ",")) != NULL) {
4235: // word length
4236: if(p[1] == '8') {
4237: selector = (selector & ~0x03) | 0x03;
4238: } else if(p[1] == '7') {
4239: selector = (selector & ~0x03) | 0x02;
4240: } else if(p[1] == '6') {
4241: selector = (selector & ~0x03) | 0x01;
4242: } else if(p[1] == '5') {
4243: selector = (selector & ~0x03) | 0x00;
4244: }
4245: if((p = strstr(p + 1, ",")) != NULL) {
4246: // stop bits
4247: float bits = atof(p + 1);
4248: if(bits > 1.0F) {
4249: selector |= 0x04;
4250: } else {
4251: selector &= ~0x04;
4252: }
4253: }
4254: }
4255: }
4256: sio_write(sio_port - 1, 3, selector | 0x80);
4257: sio_write(sio_port - 1, 0, divisor & 0xff);
4258: sio_write(sio_port - 1, 1, divisor >> 8);
4259: sio_write(sio_port - 1, 3, selector);
4260: }
4261: }
4262:
1.1.1.30 root 4263: int msdos_is_prn_path(char *path)
4264: {
4265: char full[MAX_PATH], *name;
4266:
4267: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4268: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4269: return(1);
4270: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4271: return(1);
4272: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4273: return(2);
4274: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4275: return(3);
4276: }
4277: }
4278: return(0);
4279: }
4280:
1.1.1.24 root 4281: bool msdos_is_existing_file(char *path)
4282: {
4283: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4284: WIN32_FIND_DATA FindData;
4285: HANDLE hFind;
4286:
4287: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
4288: FindClose(hFind);
4289: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
4290: }
4291: return(false);
1.1.1.8 root 4292: }
4293:
1.1.1.9 root 4294: char *msdos_search_command_com(char *command_path, char *env_path)
4295: {
4296: static char tmp[MAX_PATH];
1.1.1.28 root 4297: char path[ENV_SIZE], *file_name;
1.1.1.9 root 4298:
1.1.1.28 root 4299: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 4300: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
4301: sprintf(file_name, "COMMAND.COM");
4302: if(_access(tmp, 0) == 0) {
4303: return(tmp);
4304: }
4305: }
1.1.1.28 root 4306:
4307: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 4308: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
4309: sprintf(file_name, "COMMAND.COM");
4310: if(_access(tmp, 0) == 0) {
4311: return(tmp);
4312: }
4313: }
1.1.1.28 root 4314:
4315: // check if COMMAND.COM is in the current directory
1.1.1.9 root 4316: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4317: if(_access(tmp, 0) == 0) {
4318: return(tmp);
4319: }
4320: }
1.1.1.28 root 4321:
4322: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4323: strcpy(path, env_path);
4324: char *token = my_strtok(path, ";");
1.1.1.9 root 4325: while(token != NULL) {
1.1.1.14 root 4326: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 4327: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4328: if(_access(tmp, 0) == 0) {
4329: return(tmp);
4330: }
4331: }
4332: token = my_strtok(NULL, ";");
4333: }
4334: return(NULL);
4335: }
4336:
1.1.1.14 root 4337: int msdos_drive_number(const char *path)
1.1 root 4338: {
4339: char tmp[MAX_PATH], *name;
4340:
4341: GetFullPathName(path, MAX_PATH, tmp, &name);
4342: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4343: return(tmp[0] - 'a');
4344: } else {
4345: return(tmp[0] - 'A');
4346: }
4347: }
4348:
4349: char *msdos_volume_label(char *path)
4350: {
4351: static char tmp[MAX_PATH];
4352: char volume[] = "A:\\";
4353:
4354: if(path[1] == ':') {
4355: volume[0] = path[0];
4356: } else {
4357: volume[0] = 'A' + _getdrive() - 1;
4358: }
4359: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4360: memset(tmp, 0, sizeof(tmp));
4361: }
4362: return(tmp);
4363: }
4364:
4365: char *msdos_short_volume_label(char *label)
4366: {
4367: static char tmp[(8 + 1 + 3) + 1];
4368: char *src = label;
4369: int remain = strlen(label);
4370: char *dst_n = tmp;
4371: char *dst_e = tmp + 9;
4372:
4373: strcpy(tmp, " . ");
4374: for(int i = 0; i < 8 && remain > 0; i++) {
4375: if(msdos_lead_byte_check(*src)) {
4376: if(++i == 8) {
4377: break;
4378: }
4379: *dst_n++ = *src++;
4380: remain--;
4381: }
4382: *dst_n++ = *src++;
4383: remain--;
4384: }
4385: if(remain > 0) {
4386: for(int i = 0; i < 3 && remain > 0; i++) {
4387: if(msdos_lead_byte_check(*src)) {
4388: if(++i == 3) {
4389: break;
4390: }
4391: *dst_e++ = *src++;
4392: remain--;
4393: }
4394: *dst_e++ = *src++;
4395: remain--;
4396: }
4397: *dst_e = '\0';
4398: } else {
4399: *dst_n = '\0';
4400: }
4401: my_strupr(tmp);
4402: return(tmp);
4403: }
4404:
1.1.1.13 root 4405: errno_t msdos_maperr(unsigned long oserrno)
4406: {
4407: _doserrno = oserrno;
1.1.1.14 root 4408: switch(oserrno) {
1.1.1.13 root 4409: case ERROR_FILE_NOT_FOUND: // 2
4410: case ERROR_PATH_NOT_FOUND: // 3
4411: case ERROR_INVALID_DRIVE: // 15
4412: case ERROR_NO_MORE_FILES: // 18
4413: case ERROR_BAD_NETPATH: // 53
4414: case ERROR_BAD_NET_NAME: // 67
4415: case ERROR_BAD_PATHNAME: // 161
4416: case ERROR_FILENAME_EXCED_RANGE: // 206
4417: return ENOENT;
4418: case ERROR_TOO_MANY_OPEN_FILES: // 4
4419: return EMFILE;
4420: case ERROR_ACCESS_DENIED: // 5
4421: case ERROR_CURRENT_DIRECTORY: // 16
4422: case ERROR_NETWORK_ACCESS_DENIED: // 65
4423: case ERROR_CANNOT_MAKE: // 82
4424: case ERROR_FAIL_I24: // 83
4425: case ERROR_DRIVE_LOCKED: // 108
4426: case ERROR_SEEK_ON_DEVICE: // 132
4427: case ERROR_NOT_LOCKED: // 158
4428: case ERROR_LOCK_FAILED: // 167
4429: return EACCES;
4430: case ERROR_INVALID_HANDLE: // 6
4431: case ERROR_INVALID_TARGET_HANDLE: // 114
4432: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4433: return EBADF;
4434: case ERROR_ARENA_TRASHED: // 7
4435: case ERROR_NOT_ENOUGH_MEMORY: // 8
4436: case ERROR_INVALID_BLOCK: // 9
4437: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4438: return ENOMEM;
4439: case ERROR_BAD_ENVIRONMENT: // 10
4440: return E2BIG;
4441: case ERROR_BAD_FORMAT: // 11
4442: return ENOEXEC;
4443: case ERROR_NOT_SAME_DEVICE: // 17
4444: return EXDEV;
4445: case ERROR_FILE_EXISTS: // 80
4446: case ERROR_ALREADY_EXISTS: // 183
4447: return EEXIST;
4448: case ERROR_NO_PROC_SLOTS: // 89
4449: case ERROR_MAX_THRDS_REACHED: // 164
4450: case ERROR_NESTING_NOT_ALLOWED: // 215
4451: return EAGAIN;
4452: case ERROR_BROKEN_PIPE: // 109
4453: return EPIPE;
4454: case ERROR_DISK_FULL: // 112
4455: return ENOSPC;
4456: case ERROR_WAIT_NO_CHILDREN: // 128
4457: case ERROR_CHILD_NOT_COMPLETE: // 129
4458: return ECHILD;
4459: case ERROR_DIR_NOT_EMPTY: // 145
4460: return ENOTEMPTY;
4461: }
1.1.1.14 root 4462: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 4463: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4464: return EACCES;
4465: }
1.1.1.14 root 4466: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 4467: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4468: return ENOEXEC;
4469: }
4470: return EINVAL;
4471: }
4472:
4473: int msdos_open(const char *filename, int oflag)
4474: {
1.1.1.14 root 4475: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 4476: return _open(filename, oflag);
4477: }
1.1.1.14 root 4478:
4479: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 4480: DWORD disposition;
1.1.1.14 root 4481: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4482: default:
1.1.1.13 root 4483: case _O_EXCL:
4484: disposition = OPEN_EXISTING;
4485: break;
4486: case _O_CREAT:
4487: disposition = OPEN_ALWAYS;
4488: break;
4489: case _O_CREAT | _O_EXCL:
4490: case _O_CREAT | _O_TRUNC | _O_EXCL:
4491: disposition = CREATE_NEW;
4492: break;
4493: case _O_TRUNC:
4494: case _O_TRUNC | _O_EXCL:
4495: disposition = TRUNCATE_EXISTING;
4496: break;
4497: case _O_CREAT | _O_TRUNC:
4498: disposition = CREATE_ALWAYS;
4499: break;
4500: }
1.1.1.14 root 4501:
1.1.1.13 root 4502: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
4503: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4504: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4505: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4506: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4507: // Retry without FILE_WRITE_ATTRIBUTES.
4508: h = CreateFile(filename, GENERIC_READ,
4509: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4510: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4511: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4512: errno = msdos_maperr(GetLastError());
4513: return -1;
4514: }
4515: }
1.1.1.14 root 4516:
1.1.1.13 root 4517: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 4518: if(fd == -1) {
1.1.1.13 root 4519: CloseHandle(h);
4520: }
4521: return fd;
4522: }
4523:
1.1.1.37 root 4524: 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 4525: {
4526: static int id = 0;
4527: char full[MAX_PATH], *name;
4528:
4529: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4530: strcpy(file_handler[fd].path, full);
4531: } else {
4532: strcpy(file_handler[fd].path, path);
4533: }
1.1.1.14 root 4534: // isatty makes no distinction between CON & NUL
4535: // GetFileSize fails on CON, succeeds on NUL
4536: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
4537: info = 0x8084;
4538: atty = 0;
4539: } else if(!atty && info == 0x80d3) {
4540: info = msdos_drive_number(".");
4541: }
1.1 root 4542: file_handler[fd].valid = 1;
4543: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1.1.1.37 root 4544: file_handler[fd].atty = (sio_port == 0 && lpt_port == 0) ? atty : 0;
1.1 root 4545: file_handler[fd].mode = mode;
4546: file_handler[fd].info = info;
4547: file_handler[fd].psp = psp_seg;
1.1.1.37 root 4548: file_handler[fd].sio_port = sio_port;
4549: file_handler[fd].lpt_port = lpt_port;
1.1.1.21 root 4550:
4551: // init system file table
4552: if(fd < 20) {
4553: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
4554:
4555: memset(sft, 0, 0x3b);
4556:
4557: *(UINT16 *)(sft + 0x00) = 1;
4558: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
4559: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
4560: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
4561:
4562: if(!(file_handler[fd].info & 0x80)) {
4563: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
4564: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
4565:
4566: FILETIME time, local;
4567: HANDLE hHandle;
4568: WORD dos_date = 0, dos_time = 0;
4569: DWORD file_size = 0;
4570: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
4571: if(GetFileTime(hHandle, NULL, NULL, &time)) {
4572: FileTimeToLocalFileTime(&time, &local);
4573: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
4574: }
4575: file_size = GetFileSize(hHandle, NULL);
4576: }
4577: *(UINT16 *)(sft + 0x0d) = dos_time;
4578: *(UINT16 *)(sft + 0x0f) = dos_date;
4579: *(UINT32 *)(sft + 0x11) = file_size;
4580: }
4581:
4582: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
4583: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
4584: my_strupr(fname);
4585: my_strupr(ext);
4586: memset(sft + 0x20, 0x20, 11);
4587: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
4588: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
4589:
4590: *(UINT16 *)(sft + 0x31) = psp_seg;
4591: }
1.1 root 4592: }
4593:
1.1.1.37 root 4594: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
4595: {
4596: msdos_file_handler_open(fd, path, atty, mode, info, psp_seg, 0, 0);
4597: }
4598:
1.1 root 4599: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
4600: {
4601: strcpy(file_handler[dst].path, file_handler[src].path);
4602: file_handler[dst].valid = 1;
4603: file_handler[dst].id = file_handler[src].id;
4604: file_handler[dst].atty = file_handler[src].atty;
4605: file_handler[dst].mode = file_handler[src].mode;
4606: file_handler[dst].info = file_handler[src].info;
4607: file_handler[dst].psp = psp_seg;
1.1.1.37 root 4608: file_handler[dst].sio_port = file_handler[src].sio_port;
4609: file_handler[dst].lpt_port = file_handler[src].lpt_port;
1.1 root 4610: }
4611:
1.1.1.20 root 4612: void msdos_file_handler_close(int fd)
1.1 root 4613: {
4614: file_handler[fd].valid = 0;
1.1.1.21 root 4615:
4616: if(fd < 20) {
4617: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
4618: }
1.1 root 4619: }
4620:
1.1.1.14 root 4621: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 4622: {
1.1.1.14 root 4623: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
4624: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
4625: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 4626: }
4627:
4628: // find file
4629:
4630: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
4631: {
4632: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4633: return(0); // search directory only !!!
4634: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
4635: return(0);
4636: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
4637: return(0);
4638: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4639: return(0);
4640: } else if((attribute & required_mask) != required_mask) {
4641: return(0);
4642: } else {
4643: return(1);
4644: }
4645: }
4646:
1.1.1.13 root 4647: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
4648: {
1.1.1.14 root 4649: if(fd->cAlternateFileName[0]) {
1.1.1.42 root 4650: return(1);
1.1.1.13 root 4651: }
4652: size_t len = strlen(fd->cFileName);
1.1.1.14 root 4653: if(len > 12) {
1.1.1.42 root 4654: return(0);
1.1.1.13 root 4655: }
4656: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 4657: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.42 root 4658: return(0);
1.1.1.13 root 4659: }
1.1.1.42 root 4660: return(1);
1.1.1.13 root 4661: }
4662:
1.1 root 4663: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
4664: {
4665: FILETIME local;
4666:
4667: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
4668: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
4669: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
4670:
4671: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
4672: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
4673: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
4674:
4675: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
4676: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
4677: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
4678: }
4679:
4680: // i/o
4681:
4682: void msdos_stdio_reopen()
4683: {
4684: if(!file_handler[0].valid) {
4685: _dup2(DUP_STDIN, 0);
4686: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
4687: }
4688: if(!file_handler[1].valid) {
4689: _dup2(DUP_STDOUT, 1);
4690: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
4691: }
4692: if(!file_handler[2].valid) {
4693: _dup2(DUP_STDERR, 2);
4694: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
4695: }
1.1.1.21 root 4696: if(!file_handler[3].valid) {
4697: _dup2(DUP_STDAUX, 3);
4698: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
4699: }
4700: if(!file_handler[4].valid) {
4701: _dup2(DUP_STDPRN, 4);
1.1.1.37 root 4702: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
1.1.1.21 root 4703: }
4704: for(int i = 0; i < 5; i++) {
4705: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
4706: msdos_psp_set_file_table(i, i, current_psp);
4707: }
4708: }
1.1 root 4709: }
4710:
1.1.1.37 root 4711: int msdos_read(int fd, void *buffer, unsigned int count)
4712: {
4713: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
4714: // read from serial port
4715: int read = 0;
4716: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
4717: UINT8 *buf = (UINT8 *)buffer;
4718: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
4719: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
1.1.1.38 root 4720: DWORD timeout = timeGetTime() + 1000;
4721: while(read < count) {
4722: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x01) {
4723: buf[read++] = sio_read(file_handler[fd].sio_port - 1, 0);
4724: timeout = timeGetTime() + 1000;
4725: } else {
4726: if(timeGetTime() > timeout) {
4727: break;
4728: }
4729: Sleep(10);
1.1.1.37 root 4730: }
4731: }
4732: sio_write(file_handler[fd].sio_port - 1, 3, selector);
4733: }
4734: return(read);
4735: }
4736: return(_read(fd, buffer, count));
4737: }
4738:
1.1 root 4739: int msdos_kbhit()
4740: {
4741: msdos_stdio_reopen();
4742:
1.1.1.20 root 4743: process_t *process = msdos_process_info_get(current_psp);
4744: int fd = msdos_psp_get_file_table(0, current_psp);
4745:
4746: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4747: // stdin is redirected to file
1.1.1.20 root 4748: return(eof(fd) == 0);
1.1 root 4749: }
4750:
4751: // check keyboard status
1.1.1.35 root 4752: if(key_recv != 0) {
1.1 root 4753: return(1);
4754: }
1.1.1.35 root 4755: if(key_buf_char != NULL && key_buf_scan != NULL) {
4756: #ifdef USE_SERVICE_THREAD
4757: EnterCriticalSection(&key_buf_crit_sect);
4758: #endif
4759: bool empty = key_buf_char->empty();
4760: #ifdef USE_SERVICE_THREAD
4761: LeaveCriticalSection(&key_buf_crit_sect);
4762: #endif
4763: if(!empty) return(1);
4764: }
4765: return(_kbhit());
1.1 root 4766: }
4767:
4768: int msdos_getch_ex(int echo)
4769: {
4770: static char prev = 0;
4771:
4772: msdos_stdio_reopen();
4773:
1.1.1.20 root 4774: process_t *process = msdos_process_info_get(current_psp);
4775: int fd = msdos_psp_get_file_table(0, current_psp);
4776:
4777: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4778: // stdin is redirected to file
4779: retry:
4780: char data;
1.1.1.37 root 4781: if(msdos_read(fd, &data, 1) == 1) {
1.1 root 4782: char tmp = data;
4783: if(data == 0x0a) {
4784: if(prev == 0x0d) {
4785: goto retry; // CRLF -> skip LF
4786: } else {
4787: data = 0x0d; // LF only -> CR
4788: }
4789: }
4790: prev = tmp;
4791: return(data);
4792: }
4793: return(EOF);
4794: }
4795:
4796: // input from console
1.1.1.5 root 4797: int key_char, key_scan;
1.1.1.33 root 4798: if(key_recv != 0) {
1.1.1.5 root 4799: key_char = (key_code >> 0) & 0xff;
4800: key_scan = (key_code >> 8) & 0xff;
4801: key_code >>= 16;
1.1.1.33 root 4802: key_recv >>= 16;
1.1.1.5 root 4803: } else {
1.1.1.35 root 4804: while(key_buf_char != NULL && key_buf_scan != NULL && !m_halted) {
4805: if(key_buf_char != NULL && key_buf_scan != NULL) {
4806: #ifdef USE_SERVICE_THREAD
4807: EnterCriticalSection(&key_buf_crit_sect);
4808: #endif
4809: bool empty = key_buf_char->empty();
4810: #ifdef USE_SERVICE_THREAD
4811: LeaveCriticalSection(&key_buf_crit_sect);
4812: #endif
4813: if(!empty) break;
4814: }
1.1.1.23 root 4815: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
4816: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
4817: if(_kbhit()) {
1.1.1.32 root 4818: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4819: #ifdef USE_SERVICE_THREAD
4820: EnterCriticalSection(&key_buf_crit_sect);
4821: #endif
1.1.1.32 root 4822: key_buf_char->write(_getch());
1.1.1.35 root 4823: key_buf_scan->write(0x00);
4824: #ifdef USE_SERVICE_THREAD
4825: LeaveCriticalSection(&key_buf_crit_sect);
4826: #endif
1.1.1.32 root 4827: }
1.1.1.23 root 4828: } else {
4829: Sleep(10);
4830: }
4831: } else {
4832: if(!update_key_buffer()) {
4833: Sleep(10);
4834: }
1.1.1.14 root 4835: }
4836: }
4837: if(m_halted) {
1.1.1.33 root 4838: // insert CR to terminate input loops
1.1.1.14 root 4839: key_char = 0x0d;
4840: key_scan = 0;
1.1.1.32 root 4841: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4842: #ifdef USE_SERVICE_THREAD
4843: EnterCriticalSection(&key_buf_crit_sect);
4844: #endif
1.1.1.14 root 4845: key_char = key_buf_char->read();
4846: key_scan = key_buf_scan->read();
1.1.1.41 root 4847: // write to bottom of key buffer
4848: mem[0x43c] = (UINT8)key_char;
4849: mem[0x43d] = (UINT8)key_scan;
1.1.1.35 root 4850: #ifdef USE_SERVICE_THREAD
4851: LeaveCriticalSection(&key_buf_crit_sect);
4852: #endif
1.1.1.5 root 4853: }
1.1 root 4854: }
4855: if(echo && key_char) {
4856: msdos_putch(key_char);
4857: }
4858: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
4859: }
4860:
4861: inline int msdos_getch()
4862: {
4863: return(msdos_getch_ex(0));
4864: }
4865:
4866: inline int msdos_getche()
4867: {
4868: return(msdos_getch_ex(1));
4869: }
4870:
4871: int msdos_write(int fd, const void *buffer, unsigned int count)
4872: {
1.1.1.37 root 4873: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
4874: // write to serial port
1.1.1.38 root 4875: int written = 0;
1.1.1.37 root 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(written < count) {
4882: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x20) {
4883: sio_write(file_handler[fd].sio_port - 1, 0, buf[written++]);
4884: timeout = timeGetTime() + 1000;
4885: } else {
4886: if(timeGetTime() > timeout) {
4887: break;
4888: }
4889: Sleep(10);
4890: }
1.1.1.37 root 4891: }
4892: sio_write(file_handler[fd].sio_port - 1, 3, selector);
4893: }
1.1.1.38 root 4894: return(written);
1.1.1.37 root 4895: } else if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].lpt_port >= 1 && file_handler[fd].lpt_port <= 3) {
4896: // write to printer port
4897: UINT8 *buf = (UINT8 *)buffer;
4898: for(unsigned int i = 0; i < count; i++) {
4899: // printer_out(file_handler[fd].lpt_port - 1, buf[i]);
4900: pcbios_printer_out(file_handler[fd].lpt_port - 1, buf[i]);
4901: }
4902: return(count);
4903: } else if(fd == 1 && file_handler[1].valid && !file_handler[1].atty) {
1.1 root 4904: // CR+LF -> LF
1.1.1.37 root 4905: static int is_cr = 0;
1.1 root 4906: UINT8 *buf = (UINT8 *)buffer;
4907: for(unsigned int i = 0; i < count; i++) {
4908: UINT8 data = buf[i];
4909: if(is_cr) {
4910: if(data != 0x0a) {
4911: UINT8 tmp = 0x0d;
4912: _write(1, &tmp, 1);
4913: }
4914: _write(1, &data, 1);
4915: is_cr = 0;
4916: } else if(data == 0x0d) {
4917: is_cr = 1;
4918: } else {
4919: _write(1, &data, 1);
4920: }
4921: }
4922: return(count);
4923: }
1.1.1.14 root 4924: vram_flush();
1.1 root 4925: return(_write(fd, buffer, count));
4926: }
4927:
4928: void msdos_putch(UINT8 data)
1.1.1.35 root 4929: #ifdef USE_SERVICE_THREAD
4930: {
4931: EnterCriticalSection(&putch_crit_sect);
4932: msdos_putch_tmp(data);
4933: LeaveCriticalSection(&putch_crit_sect);
4934: }
4935: void msdos_putch_tmp(UINT8 data)
4936: #endif
1.1 root 4937: {
1.1.1.34 root 4938: CONSOLE_SCREEN_BUFFER_INFO csbi;
4939: SMALL_RECT rect;
4940: COORD co;
1.1 root 4941: static int p = 0;
4942: static int is_kanji = 0;
4943: static int is_esc = 0;
4944: static int stored_x;
4945: static int stored_y;
4946: static WORD stored_a;
1.1.1.20 root 4947: static char tmp[64], out[64];
1.1 root 4948:
4949: msdos_stdio_reopen();
4950:
1.1.1.20 root 4951: process_t *process = msdos_process_info_get(current_psp);
4952: int fd = msdos_psp_get_file_table(1, current_psp);
4953:
4954: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4955: // stdout is redirected to file
1.1.1.20 root 4956: msdos_write(fd, &data, 1);
1.1 root 4957: return;
4958: }
1.1.1.23 root 4959: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4960:
4961: // output to console
4962: tmp[p++] = data;
4963:
1.1.1.14 root 4964: vram_flush();
4965:
1.1 root 4966: if(is_kanji) {
4967: // kanji character
4968: is_kanji = 0;
4969: } else if(is_esc) {
4970: // escape sequense
4971: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
4972: p = is_esc = 0;
4973: } else if(tmp[1] == '=' && p == 4) {
4974: co.X = tmp[3] - 0x20;
1.1.1.14 root 4975: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 4976: SetConsoleCursorPosition(hStdout, co);
4977: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 4978: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 4979: cursor_moved = false;
4980: p = is_esc = 0;
4981: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
4982: GetConsoleScreenBufferInfo(hStdout, &csbi);
4983: co.X = csbi.dwCursorPosition.X;
4984: co.Y = csbi.dwCursorPosition.Y;
4985: WORD wAttributes = csbi.wAttributes;
4986:
4987: if(tmp[1] == 'D') {
4988: co.Y++;
4989: } else if(tmp[1] == 'E') {
4990: co.X = 0;
4991: co.Y++;
4992: } else if(tmp[1] == 'M') {
4993: co.Y--;
4994: } else if(tmp[1] == '*') {
1.1.1.14 root 4995: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4996: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4997: co.X = 0;
4998: co.Y = csbi.srWindow.Top;
1.1 root 4999: } else if(tmp[1] == '[') {
5000: int param[256], params = 0;
5001: memset(param, 0, sizeof(param));
5002: for(int i = 2; i < p; i++) {
5003: if(tmp[i] >= '0' && tmp[i] <= '9') {
5004: param[params] *= 10;
5005: param[params] += tmp[i] - '0';
5006: } else {
5007: params++;
5008: }
5009: }
5010: if(data == 'A') {
1.1.1.14 root 5011: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 5012: } else if(data == 'B') {
1.1.1.14 root 5013: co.Y += (params == 0) ? 1 : param[0];
1.1 root 5014: } else if(data == 'C') {
1.1.1.14 root 5015: co.X += (params == 0) ? 1 : param[0];
1.1 root 5016: } else if(data == 'D') {
1.1.1.14 root 5017: co.X -= (params == 0) ? 1 : param[0];
1.1 root 5018: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 5019: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
5020: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 5021: } else if(data == 'J') {
1.1.1.14 root 5022: clear_scr_buffer(csbi.wAttributes);
1.1 root 5023: if(param[0] == 0) {
5024: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5025: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5026: if(co.Y < csbi.srWindow.Bottom) {
5027: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5028: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5029: }
5030: } else if(param[0] == 1) {
1.1.1.14 root 5031: if(co.Y > csbi.srWindow.Top) {
5032: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
5033: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5034: }
5035: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5036: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5037: } else if(param[0] == 2) {
1.1.1.14 root 5038: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5039: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5040: co.X = co.Y = 0;
5041: }
5042: } else if(data == 'K') {
1.1.1.14 root 5043: clear_scr_buffer(csbi.wAttributes);
1.1 root 5044: if(param[0] == 0) {
5045: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5046: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5047: } else if(param[0] == 1) {
5048: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5049: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5050: } else if(param[0] == 2) {
5051: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5052: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5053: }
5054: } else if(data == 'L') {
1.1.1.14 root 5055: if(params == 0) {
5056: param[0] = 1;
1.1 root 5057: }
1.1.1.14 root 5058: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5059: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5060: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5061: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5062: clear_scr_buffer(csbi.wAttributes);
1.1 root 5063: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 5064: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5065: co.X = 0;
5066: } else if(data == 'M') {
1.1.1.14 root 5067: if(params == 0) {
5068: param[0] = 1;
5069: }
5070: if(co.Y + param[0] > csbi.srWindow.Bottom) {
5071: clear_scr_buffer(csbi.wAttributes);
5072: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5073: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5074: } else {
1.1.1.14 root 5075: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5076: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5077: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5078: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5079: clear_scr_buffer(csbi.wAttributes);
1.1 root 5080: }
5081: co.X = 0;
5082: } else if(data == 'h') {
5083: if(tmp[2] == '>' && tmp[3] == '5') {
5084: CONSOLE_CURSOR_INFO cur;
5085: GetConsoleCursorInfo(hStdout, &cur);
5086: if(cur.bVisible) {
5087: cur.bVisible = FALSE;
1.1.1.14 root 5088: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5089: }
5090: }
5091: } else if(data == 'l') {
5092: if(tmp[2] == '>' && tmp[3] == '5') {
5093: CONSOLE_CURSOR_INFO cur;
5094: GetConsoleCursorInfo(hStdout, &cur);
5095: if(!cur.bVisible) {
5096: cur.bVisible = TRUE;
1.1.1.14 root 5097: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5098: }
5099: }
5100: } else if(data == 'm') {
5101: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
5102: int reverse = 0, hidden = 0;
5103: for(int i = 0; i < params; i++) {
5104: if(param[i] == 1) {
5105: wAttributes |= FOREGROUND_INTENSITY;
5106: } else if(param[i] == 4) {
5107: wAttributes |= COMMON_LVB_UNDERSCORE;
5108: } else if(param[i] == 7) {
5109: reverse = 1;
5110: } else if(param[i] == 8 || param[i] == 16) {
5111: hidden = 1;
5112: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
5113: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
5114: if(param[i] >= 17 && param[i] <= 23) {
5115: param[i] -= 16;
5116: } else {
5117: param[i] -= 30;
5118: }
5119: if(param[i] & 1) {
5120: wAttributes |= FOREGROUND_RED;
5121: }
5122: if(param[i] & 2) {
5123: wAttributes |= FOREGROUND_GREEN;
5124: }
5125: if(param[i] & 4) {
5126: wAttributes |= FOREGROUND_BLUE;
5127: }
5128: } else if(param[i] >= 40 && param[i] <= 47) {
5129: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
5130: if((param[i] - 40) & 1) {
5131: wAttributes |= BACKGROUND_RED;
5132: }
5133: if((param[i] - 40) & 2) {
5134: wAttributes |= BACKGROUND_GREEN;
5135: }
5136: if((param[i] - 40) & 4) {
5137: wAttributes |= BACKGROUND_BLUE;
5138: }
5139: }
5140: }
5141: if(reverse) {
5142: wAttributes &= ~0xff;
5143: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
5144: }
5145: if(hidden) {
5146: wAttributes &= ~0x0f;
5147: wAttributes |= (wAttributes >> 4) & 0x0f;
5148: }
5149: } else if(data == 'n') {
5150: if(param[0] == 6) {
5151: char tmp[16];
5152: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
5153: int len = strlen(tmp);
1.1.1.32 root 5154: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 5155: #ifdef USE_SERVICE_THREAD
5156: EnterCriticalSection(&key_buf_crit_sect);
5157: #endif
1.1.1.32 root 5158: for(int i = 0; i < len; i++) {
5159: key_buf_char->write(tmp[i]);
5160: key_buf_scan->write(0x00);
5161: }
1.1.1.35 root 5162: #ifdef USE_SERVICE_THREAD
5163: LeaveCriticalSection(&key_buf_crit_sect);
5164: #endif
1.1 root 5165: }
5166: }
5167: } else if(data == 's') {
5168: stored_x = co.X;
5169: stored_y = co.Y;
5170: stored_a = wAttributes;
5171: } else if(data == 'u') {
5172: co.X = stored_x;
5173: co.Y = stored_y;
5174: wAttributes = stored_a;
5175: }
5176: }
5177: if(co.X < 0) {
5178: co.X = 0;
5179: } else if(co.X >= csbi.dwSize.X) {
5180: co.X = csbi.dwSize.X - 1;
5181: }
1.1.1.14 root 5182: if(co.Y < csbi.srWindow.Top) {
5183: co.Y = csbi.srWindow.Top;
5184: } else if(co.Y > csbi.srWindow.Bottom) {
5185: co.Y = csbi.srWindow.Bottom;
1.1 root 5186: }
5187: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
5188: SetConsoleCursorPosition(hStdout, co);
5189: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5190: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 5191: cursor_moved = false;
5192: }
5193: if(wAttributes != csbi.wAttributes) {
5194: SetConsoleTextAttribute(hStdout, wAttributes);
5195: }
5196: p = is_esc = 0;
5197: }
5198: return;
5199: } else {
5200: if(msdos_lead_byte_check(data)) {
5201: is_kanji = 1;
5202: return;
5203: } else if(data == 0x1b) {
5204: is_esc = 1;
5205: return;
5206: }
5207: }
1.1.1.20 root 5208:
5209: DWORD q = 0, num;
5210: is_kanji = 0;
5211: for(int i = 0; i < p; i++) {
5212: UINT8 c = tmp[i];
5213: if(is_kanji) {
5214: is_kanji = 0;
5215: } else if(msdos_lead_byte_check(data)) {
5216: is_kanji = 1;
5217: } else if(msdos_ctrl_code_check(data)) {
5218: out[q++] = '^';
5219: c += 'A' - 1;
5220: }
5221: out[q++] = c;
5222: }
1.1.1.34 root 5223: if(q == 1 && out[0] == 0x08) {
5224: // back space
5225: GetConsoleScreenBufferInfo(hStdout, &csbi);
5226: if(csbi.dwCursorPosition.X > 0) {
5227: co.X = csbi.dwCursorPosition.X - 1;
5228: co.Y = csbi.dwCursorPosition.Y;
5229: SetConsoleCursorPosition(hStdout, co);
5230: } else if(csbi.dwCursorPosition.Y > 0) {
5231: co.X = csbi.dwSize.X - 1;
5232: co.Y = csbi.dwCursorPosition.Y - 1;
5233: SetConsoleCursorPosition(hStdout, co);
5234: } else {
5235: WriteConsole(hStdout, out, q, &num, NULL); // to make sure
5236: }
5237: } else {
5238: WriteConsole(hStdout, out, q, &num, NULL);
5239: }
1.1 root 5240: p = 0;
1.1.1.14 root 5241:
1.1.1.15 root 5242: if(!restore_console_on_exit) {
5243: GetConsoleScreenBufferInfo(hStdout, &csbi);
5244: scr_top = csbi.srWindow.Top;
5245: }
1.1 root 5246: cursor_moved = true;
5247: }
5248:
5249: int msdos_aux_in()
5250: {
1.1.1.21 root 5251: msdos_stdio_reopen();
5252:
1.1.1.20 root 5253: process_t *process = msdos_process_info_get(current_psp);
5254: int fd = msdos_psp_get_file_table(3, current_psp);
5255:
5256: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 5257: char data = 0;
1.1.1.37 root 5258: msdos_read(fd, &data, 1);
1.1 root 5259: return(data);
5260: } else {
5261: return(EOF);
5262: }
5263: }
5264:
5265: void msdos_aux_out(char data)
5266: {
1.1.1.21 root 5267: msdos_stdio_reopen();
5268:
1.1.1.20 root 5269: process_t *process = msdos_process_info_get(current_psp);
5270: int fd = msdos_psp_get_file_table(3, current_psp);
5271:
5272: if(fd < process->max_files && file_handler[fd].valid) {
5273: msdos_write(fd, &data, 1);
1.1 root 5274: }
5275: }
5276:
5277: void msdos_prn_out(char data)
5278: {
1.1.1.21 root 5279: msdos_stdio_reopen();
5280:
1.1.1.20 root 5281: process_t *process = msdos_process_info_get(current_psp);
5282: int fd = msdos_psp_get_file_table(4, current_psp);
5283:
5284: if(fd < process->max_files && file_handler[fd].valid) {
5285: msdos_write(fd, &data, 1);
1.1 root 5286: }
5287: }
5288:
5289: // memory control
5290:
1.1.1.39 root 5291: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs, char *prog_name)
1.1 root 5292: {
5293: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5294:
5295: mcb->mz = mz;
5296: mcb->psp = psp;
1.1.1.30 root 5297: mcb->paragraphs = paragraphs;
1.1.1.39 root 5298:
5299: if(prog_name != NULL) {
5300: memset(mcb->prog_name, 0, 8);
5301: memcpy(mcb->prog_name, prog_name, min(8, strlen(prog_name)));
5302: }
1.1 root 5303: return(mcb);
5304: }
5305:
1.1.1.39 root 5306: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
5307: {
5308: return(msdos_mcb_create(mcb_seg, mz, psp, paragraphs, NULL));
5309: }
5310:
1.1 root 5311: void msdos_mcb_check(mcb_t *mcb)
5312: {
5313: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 5314: #if 0
5315: // shutdown now !!!
5316: fatalerror("broken memory control block\n");
5317: #else
5318: // return error code and continue
5319: throw(0x07); // broken memory control block
5320: #endif
1.1 root 5321: }
5322: }
5323:
1.1.1.39 root 5324: void msdos_mem_split(int seg, int paragraphs)
1.1 root 5325: {
5326: int mcb_seg = seg - 1;
5327: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5328: msdos_mcb_check(mcb);
5329:
1.1.1.30 root 5330: if(mcb->paragraphs > paragraphs) {
1.1 root 5331: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 5332: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 5333:
5334: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5335: mcb->mz = 'M';
1.1.1.30 root 5336: mcb->paragraphs = paragraphs;
1.1 root 5337: }
5338: }
5339:
5340: void msdos_mem_merge(int seg)
5341: {
5342: int mcb_seg = seg - 1;
5343: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5344: msdos_mcb_check(mcb);
5345:
5346: while(1) {
5347: if(mcb->mz == 'Z') {
5348: break;
5349: }
1.1.1.30 root 5350: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 5351: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5352: msdos_mcb_check(next_mcb);
5353:
5354: if(next_mcb->psp != 0) {
5355: break;
5356: }
5357: mcb->mz = next_mcb->mz;
1.1.1.30 root 5358: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 5359: }
5360: }
5361:
1.1.1.8 root 5362: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 5363: {
5364: while(1) {
5365: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5366: bool last_block;
1.1 root 5367:
1.1.1.14 root 5368: if(mcb->psp == 0) {
5369: msdos_mem_merge(mcb_seg + 1);
5370: } else {
5371: msdos_mcb_check(mcb);
5372: }
1.1.1.33 root 5373: if(!(last_block = (mcb->mz == 'Z'))) {
5374: // check if the next is dummy mcb to link to umb
5375: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5376: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5377: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5378: }
5379: if(!(new_process && !last_block)) {
1.1.1.30 root 5380: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 5381: msdos_mem_split(mcb_seg + 1, paragraphs);
5382: mcb->psp = current_psp;
5383: return(mcb_seg + 1);
5384: }
5385: }
5386: if(mcb->mz == 'Z') {
5387: break;
5388: }
1.1.1.30 root 5389: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5390: }
5391: return(-1);
5392: }
5393:
5394: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5395: {
5396: int mcb_seg = seg - 1;
5397: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5398: msdos_mcb_check(mcb);
1.1.1.30 root 5399: int current_paragraphs = mcb->paragraphs;
1.1 root 5400:
5401: msdos_mem_merge(seg);
1.1.1.30 root 5402: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 5403: if(max_paragraphs) {
1.1.1.30 root 5404: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 5405: }
1.1 root 5406: msdos_mem_split(seg, current_paragraphs);
5407: return(-1);
5408: }
5409: msdos_mem_split(seg, paragraphs);
5410: return(0);
5411: }
5412:
5413: void msdos_mem_free(int seg)
5414: {
5415: int mcb_seg = seg - 1;
5416: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5417: msdos_mcb_check(mcb);
5418:
5419: mcb->psp = 0;
5420: msdos_mem_merge(seg);
5421: }
5422:
1.1.1.8 root 5423: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 5424: {
5425: int max_paragraphs = 0;
5426:
5427: while(1) {
5428: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5429: bool last_block;
5430:
1.1 root 5431: msdos_mcb_check(mcb);
5432:
1.1.1.33 root 5433: if(!(last_block = (mcb->mz == 'Z'))) {
5434: // check if the next is dummy mcb to link to umb
5435: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5436: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5437: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5438: }
5439: if(!(new_process && !last_block)) {
1.1.1.30 root 5440: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
5441: max_paragraphs = mcb->paragraphs;
1.1 root 5442: }
5443: }
5444: if(mcb->mz == 'Z') {
5445: break;
5446: }
1.1.1.30 root 5447: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5448: }
1.1.1.14 root 5449: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 5450: }
5451:
1.1.1.8 root 5452: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
5453: {
5454: int last_seg = -1;
5455:
5456: while(1) {
5457: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5458: msdos_mcb_check(mcb);
5459:
1.1.1.14 root 5460: if(mcb->psp == psp) {
1.1.1.8 root 5461: last_seg = mcb_seg;
5462: }
1.1.1.14 root 5463: if(mcb->mz == 'Z') {
5464: break;
5465: }
1.1.1.30 root 5466: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 5467: }
5468: return(last_seg);
5469: }
5470:
1.1.1.19 root 5471: int msdos_mem_get_umb_linked()
5472: {
1.1.1.33 root 5473: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5474: msdos_mcb_check(mcb);
1.1.1.19 root 5475:
1.1.1.33 root 5476: if(mcb->mz == 'M') {
5477: return(-1);
1.1.1.19 root 5478: }
5479: return(0);
5480: }
5481:
1.1.1.33 root 5482: void msdos_mem_link_umb()
1.1.1.19 root 5483: {
1.1.1.33 root 5484: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5485: msdos_mcb_check(mcb);
1.1.1.19 root 5486:
1.1.1.33 root 5487: mcb->mz = 'M';
5488: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
1.1.1.39 root 5489:
5490: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 5491: }
5492:
1.1.1.33 root 5493: void msdos_mem_unlink_umb()
1.1.1.19 root 5494: {
1.1.1.33 root 5495: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5496: msdos_mcb_check(mcb);
1.1.1.19 root 5497:
1.1.1.33 root 5498: mcb->mz = 'Z';
5499: mcb->paragraphs = 0;
1.1.1.39 root 5500:
5501: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 5502: }
5503:
1.1.1.29 root 5504: #ifdef SUPPORT_HMA
5505:
5506: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
5507: {
5508: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5509:
5510: mcb->ms[0] = 'M';
5511: mcb->ms[1] = 'S';
5512: mcb->owner = owner;
5513: mcb->size = size;
5514: mcb->next = next;
5515: return(mcb);
5516: }
5517:
5518: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
5519: {
5520: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
5521: }
5522:
5523: int msdos_hma_mem_split(int offset, int size)
5524: {
5525: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5526:
5527: if(!msdos_is_hma_mcb_valid(mcb)) {
5528: return(-1);
5529: }
5530: if(mcb->size >= size + 0x10) {
5531: int new_offset = offset + 0x10 + size;
5532: int new_size = mcb->size - 0x10 - size;
5533:
5534: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
5535: mcb->size = size;
5536: mcb->next = new_offset;
5537: return(0);
5538: }
5539: return(-1);
5540: }
5541:
5542: void msdos_hma_mem_merge(int offset)
5543: {
5544: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5545:
5546: if(!msdos_is_hma_mcb_valid(mcb)) {
5547: return;
5548: }
5549: while(1) {
5550: if(mcb->next == 0) {
5551: break;
5552: }
5553: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
5554:
5555: if(!msdos_is_hma_mcb_valid(next_mcb)) {
5556: return;
5557: }
5558: if(next_mcb->owner != 0) {
5559: break;
5560: }
5561: mcb->size += 0x10 + next_mcb->size;
5562: mcb->next = next_mcb->next;
5563: }
5564: }
5565:
5566: int msdos_hma_mem_alloc(int size, UINT16 owner)
5567: {
5568: int offset = 0x10; // first mcb in HMA
5569:
5570: while(1) {
5571: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5572:
5573: if(!msdos_is_hma_mcb_valid(mcb)) {
5574: return(-1);
5575: }
5576: if(mcb->owner == 0) {
5577: msdos_hma_mem_merge(offset);
5578: }
5579: if(mcb->owner == 0 && mcb->size >= size) {
5580: msdos_hma_mem_split(offset, size);
5581: mcb->owner = owner;
5582: return(offset);
5583: }
5584: if(mcb->next == 0) {
5585: break;
5586: }
5587: offset = mcb->next;
5588: }
5589: return(-1);
5590: }
5591:
5592: int msdos_hma_mem_realloc(int offset, int size)
5593: {
5594: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5595:
5596: if(!msdos_is_hma_mcb_valid(mcb)) {
5597: return(-1);
5598: }
5599: if(mcb->size < size) {
5600: return(-1);
5601: }
5602: msdos_hma_mem_split(offset, size);
5603: return(0);
5604: }
5605:
5606: void msdos_hma_mem_free(int offset)
5607: {
5608: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5609:
5610: if(!msdos_is_hma_mcb_valid(mcb)) {
5611: return;
5612: }
5613: mcb->owner = 0;
5614: msdos_hma_mem_merge(offset);
5615: }
5616:
5617: int msdos_hma_mem_get_free(int *available_offset)
5618: {
5619: int offset = 0x10; // first mcb in HMA
5620: int size = 0;
5621:
5622: while(1) {
5623: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5624:
5625: if(!msdos_is_hma_mcb_valid(mcb)) {
5626: return(0);
5627: }
5628: if(mcb->owner == 0 && size < mcb->size) {
5629: if(available_offset != NULL) {
5630: *available_offset = offset;
5631: }
5632: size = mcb->size;
5633: }
5634: if(mcb->next == 0) {
5635: break;
5636: }
5637: offset = mcb->next;
5638: }
5639: return(size);
5640: }
5641:
5642: #endif
5643:
1.1 root 5644: // environment
5645:
5646: void msdos_env_set_argv(int env_seg, char *argv)
5647: {
5648: char *dst = (char *)(mem + (env_seg << 4));
5649:
5650: while(1) {
5651: if(dst[0] == 0) {
5652: break;
5653: }
5654: dst += strlen(dst) + 1;
5655: }
5656: *dst++ = 0; // end of environment
5657: *dst++ = 1; // top of argv[0]
5658: *dst++ = 0;
5659: memcpy(dst, argv, strlen(argv));
5660: dst += strlen(argv);
5661: *dst++ = 0;
5662: *dst++ = 0;
5663: }
5664:
5665: char *msdos_env_get_argv(int env_seg)
5666: {
5667: static char env[ENV_SIZE];
5668: char *src = env;
5669:
5670: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5671: while(1) {
5672: if(src[0] == 0) {
5673: if(src[1] == 1) {
5674: return(src + 3);
5675: }
5676: break;
5677: }
5678: src += strlen(src) + 1;
5679: }
5680: return(NULL);
5681: }
5682:
5683: char *msdos_env_get(int env_seg, const char *name)
5684: {
5685: static char env[ENV_SIZE];
5686: char *src = env;
5687:
5688: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5689: while(1) {
5690: if(src[0] == 0) {
5691: break;
5692: }
5693: int len = strlen(src);
5694: char *n = my_strtok(src, "=");
5695: char *v = src + strlen(n) + 1;
5696:
5697: if(_stricmp(name, n) == 0) {
5698: return(v);
5699: }
5700: src += len + 1;
5701: }
5702: return(NULL);
5703: }
5704:
5705: void msdos_env_set(int env_seg, char *name, char *value)
5706: {
5707: char env[ENV_SIZE];
5708: char *src = env;
5709: char *dst = (char *)(mem + (env_seg << 4));
5710: char *argv = msdos_env_get_argv(env_seg);
5711: int done = 0;
5712:
5713: memcpy(src, dst, ENV_SIZE);
5714: memset(dst, 0, ENV_SIZE);
5715: while(1) {
5716: if(src[0] == 0) {
5717: break;
5718: }
5719: int len = strlen(src);
5720: char *n = my_strtok(src, "=");
5721: char *v = src + strlen(n) + 1;
5722: char tmp[1024];
5723:
5724: if(_stricmp(name, n) == 0) {
5725: sprintf(tmp, "%s=%s", n, value);
5726: done = 1;
5727: } else {
5728: sprintf(tmp, "%s=%s", n, v);
5729: }
5730: memcpy(dst, tmp, strlen(tmp));
5731: dst += strlen(tmp) + 1;
5732: src += len + 1;
5733: }
5734: if(!done) {
5735: char tmp[1024];
5736:
5737: sprintf(tmp, "%s=%s", name, value);
5738: memcpy(dst, tmp, strlen(tmp));
5739: dst += strlen(tmp) + 1;
5740: }
5741: if(argv) {
5742: *dst++ = 0; // end of environment
5743: *dst++ = 1; // top of argv[0]
5744: *dst++ = 0;
5745: memcpy(dst, argv, strlen(argv));
5746: dst += strlen(argv);
5747: *dst++ = 0;
5748: *dst++ = 0;
5749: }
5750: }
5751:
5752: // process
5753:
1.1.1.8 root 5754: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 5755: {
5756: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5757:
5758: memset(psp, 0, PSP_SIZE);
5759: psp->exit[0] = 0xcd;
5760: psp->exit[1] = 0x20;
1.1.1.8 root 5761: psp->first_mcb = mcb_seg;
1.1 root 5762: psp->far_call = 0xea;
5763: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
5764: psp->cpm_entry.w.h = 0xf000;
5765: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5766: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5767: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5768: psp->parent_psp = parent_psp;
1.1.1.20 root 5769: if(parent_psp == (UINT16)-1) {
5770: for(int i = 0; i < 20; i++) {
5771: if(file_handler[i].valid) {
5772: psp->file_table[i] = i;
5773: } else {
5774: psp->file_table[i] = 0xff;
5775: }
1.1 root 5776: }
1.1.1.20 root 5777: } else {
5778: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 5779: }
5780: psp->env_seg = env_seg;
5781: psp->stack.w.l = REG16(SP);
1.1.1.3 root 5782: psp->stack.w.h = SREG(SS);
1.1.1.14 root 5783: psp->file_table_size = 20;
5784: psp->file_table_ptr.w.l = 0x18;
5785: psp->file_table_ptr.w.h = psp_seg;
1.1 root 5786: psp->service[0] = 0xcd;
5787: psp->service[1] = 0x21;
5788: psp->service[2] = 0xcb;
5789: return(psp);
5790: }
5791:
1.1.1.20 root 5792: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
5793: {
5794: if(psp_seg && fd < 20) {
5795: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5796: psp->file_table[fd] = value;
5797: }
5798: }
5799:
5800: int msdos_psp_get_file_table(int fd, int psp_seg)
5801: {
5802: if(psp_seg && fd < 20) {
5803: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5804: fd = psp->file_table[fd];
5805: }
5806: return fd;
5807: }
5808:
1.1 root 5809: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
5810: {
5811: // load command file
5812: int fd = -1;
5813: int dos_command = 0;
1.1.1.24 root 5814: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1.1.38 root 5815: char pipe_stdin_path[MAX_PATH] = {0};
5816: char pipe_stdout_path[MAX_PATH] = {0};
1.1.1.39 root 5817: char pipe_stderr_path[MAX_PATH] = {0};
1.1 root 5818:
5819: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5820: int opt_len = mem[opt_ofs];
5821: memset(opt, 0, sizeof(opt));
5822: memcpy(opt, mem + opt_ofs + 1, opt_len);
5823:
1.1.1.14 root 5824: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
5825: // this is a batch file, run command.com
5826: char tmp[MAX_PATH];
5827: if(opt_len != 0) {
5828: sprintf(tmp, "/C %s %s", cmd, opt);
5829: } else {
5830: sprintf(tmp, "/C %s", cmd);
5831: }
5832: strcpy(opt, tmp);
5833: opt_len = strlen(opt);
5834: mem[opt_ofs] = opt_len;
5835: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5836: strcpy(command, comspec_path);
5837: strcpy(name_tmp, "COMMAND.COM");
5838: } else {
5839: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
5840: // redirect C:\COMMAND.COM to comspec_path
5841: strcpy(command, comspec_path);
5842: } else {
5843: strcpy(command, cmd);
5844: }
1.1.1.24 root 5845: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
5846: return(-1);
5847: }
1.1.1.14 root 5848: memset(name_tmp, 0, sizeof(name_tmp));
5849: strcpy(name_tmp, name);
5850:
5851: // check command.com
1.1.1.38 root 5852: if((_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) && _access(comspec_path, 0) != 0) {
5853: // we can not load command.com, so run program directly if "command /c (program)" is specified
1.1.1.14 root 5854: if(opt_len == 0) {
5855: // process_t *current_process = msdos_process_info_get(current_psp);
5856: process_t *current_process = NULL;
5857: for(int i = 0; i < MAX_PROCESS; i++) {
5858: if(process[i].psp == current_psp) {
5859: current_process = &process[i];
5860: break;
5861: }
5862: }
5863: if(current_process != NULL) {
5864: param->cmd_line.dw = current_process->dta.dw;
5865: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5866: opt_len = mem[opt_ofs];
5867: memset(opt, 0, sizeof(opt));
5868: memcpy(opt, mem + opt_ofs + 1, opt_len);
5869: }
5870: }
5871: for(int i = 0; i < opt_len; i++) {
5872: if(opt[i] == ' ') {
5873: continue;
5874: }
5875: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
5876: for(int j = i + 3; j < opt_len; j++) {
5877: if(opt[j] == ' ') {
5878: continue;
5879: }
5880: char *token = my_strtok(opt + j, " ");
5881:
1.1.1.38 root 5882: strcpy(command, token);
5883: char tmp[MAX_PATH];
5884: strcpy(tmp, token + strlen(token) + 1);
1.1.1.39 root 5885: strcpy(opt, "");
5886: for(int i = 0; i < strlen(tmp); i++) {
5887: if(tmp[i] != ' ') {
5888: strcpy(opt, tmp + i);
5889: break;
5890: }
5891: }
5892: strcpy(tmp, opt);
1.1.1.38 root 5893:
5894: if(al == 0x00) {
1.1.1.39 root 5895: #define GET_FILE_PATH() { \
5896: if(token[0] != '>' && token[0] != '<') { \
5897: token++; \
5898: } \
5899: token++; \
5900: while(*token == ' ') { \
5901: token++; \
5902: } \
5903: char *ptr = token; \
5904: while(*ptr != ' ' && *ptr != '\r' && *ptr != '\0') { \
5905: ptr++; \
5906: } \
5907: *ptr = '\0'; \
5908: }
5909: if((token = strstr(opt, "0<")) != NULL || (token = strstr(opt, "<")) != NULL) {
5910: GET_FILE_PATH();
1.1.1.38 root 5911: strcpy(pipe_stdin_path, token);
5912: strcpy(opt, tmp);
5913: }
1.1.1.39 root 5914: if((token = strstr(opt, "1>")) != NULL || (token = strstr(opt, ">")) != NULL) {
5915: GET_FILE_PATH();
1.1.1.38 root 5916: strcpy(pipe_stdout_path, token);
5917: strcpy(opt, tmp);
5918: }
1.1.1.39 root 5919: if((token = strstr(opt, "2>")) != NULL) {
5920: GET_FILE_PATH();
5921: strcpy(pipe_stderr_path, token);
5922: strcpy(opt, tmp);
5923: }
5924: #undef GET_FILE_PATH
5925:
5926: if((token = strstr(opt, "0<")) != NULL) {
5927: *token = '\0';
5928: }
5929: if((token = strstr(opt, "1>")) != NULL) {
5930: *token = '\0';
5931: }
5932: if((token = strstr(opt, "2>")) != NULL) {
5933: *token = '\0';
5934: }
1.1.1.38 root 5935: if((token = strstr(opt, "<")) != NULL) {
5936: *token = '\0';
5937: }
5938: if((token = strstr(opt, ">")) != NULL) {
5939: *token = '\0';
5940: }
1.1.1.14 root 5941: }
1.1.1.39 root 5942: for(int i = strlen(opt) - 1; i >= 0 && opt[i] == ' '; i--) {
5943: opt[i] = '\0';
5944: }
1.1.1.38 root 5945: opt_len = strlen(opt);
5946: mem[opt_ofs] = opt_len;
5947: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5948: dos_command = 1;
1.1.1.14 root 5949: break;
1.1 root 5950: }
5951: }
1.1.1.14 root 5952: break;
1.1 root 5953: }
5954: }
5955: }
5956:
5957: // load command file
5958: strcpy(path, command);
5959: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5960: sprintf(path, "%s.COM", command);
5961: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5962: sprintf(path, "%s.EXE", command);
5963: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 5964: sprintf(path, "%s.BAT", command);
5965: if(_access(path, 0) == 0) {
5966: // this is a batch file, run command.com
5967: char tmp[MAX_PATH];
5968: if(opt_len != 0) {
5969: sprintf(tmp, "/C %s %s", path, opt);
5970: } else {
5971: sprintf(tmp, "/C %s", path);
5972: }
5973: strcpy(opt, tmp);
5974: opt_len = strlen(opt);
5975: mem[opt_ofs] = opt_len;
5976: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5977: strcpy(path, comspec_path);
5978: strcpy(name_tmp, "COMMAND.COM");
5979: fd = _open(path, _O_RDONLY | _O_BINARY);
5980: } else {
5981: // search path in parent environments
5982: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5983: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
5984: if(env != NULL) {
5985: char env_path[4096];
5986: strcpy(env_path, env);
5987: char *token = my_strtok(env_path, ";");
5988:
5989: while(token != NULL) {
5990: if(strlen(token) != 0) {
5991: sprintf(path, "%s", msdos_combine_path(token, command));
5992: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5993: break;
5994: }
5995: sprintf(path, "%s.COM", msdos_combine_path(token, command));
5996: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5997: break;
5998: }
5999: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
6000: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
6001: break;
6002: }
6003: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
6004: if(_access(path, 0) == 0) {
6005: // this is a batch file, run command.com
6006: char tmp[MAX_PATH];
6007: if(opt_len != 0) {
6008: sprintf(tmp, "/C %s %s", path, opt);
6009: } else {
6010: sprintf(tmp, "/C %s", path);
6011: }
6012: strcpy(opt, tmp);
6013: opt_len = strlen(opt);
6014: mem[opt_ofs] = opt_len;
6015: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
6016: strcpy(path, comspec_path);
6017: strcpy(name_tmp, "COMMAND.COM");
6018: fd = _open(path, _O_RDONLY | _O_BINARY);
6019: break;
6020: }
1.1.1.8 root 6021: }
1.1.1.14 root 6022: token = my_strtok(NULL, ";");
1.1 root 6023: }
6024: }
6025: }
6026: }
6027: }
6028: }
6029: if(fd == -1) {
1.1.1.38 root 6030: // we can not find command.com in the path, so open comspec_path
6031: if(_stricmp(command, "COMMAND.COM") == 0 || _stricmp(command, "COMMAND") == 0) {
6032: strcpy(command, comspec_path);
6033: strcpy(path, command);
6034: fd = _open(path, _O_RDONLY | _O_BINARY);
6035: }
6036: }
6037: if(fd == -1) {
1.1 root 6038: if(dos_command) {
6039: // may be dos command
6040: char tmp[MAX_PATH];
6041: sprintf(tmp, "%s %s", command, opt);
6042: system(tmp);
6043: return(0);
6044: } else {
6045: return(-1);
6046: }
6047: }
6048: _read(fd, file_buffer, sizeof(file_buffer));
6049: _close(fd);
6050:
6051: // copy environment
1.1.1.29 root 6052: int umb_linked, env_seg, psp_seg;
1.1 root 6053:
1.1.1.29 root 6054: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6055: msdos_mem_unlink_umb();
6056: }
1.1.1.8 root 6057: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 6058: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
6059: if(umb_linked != 0) {
6060: msdos_mem_link_umb();
6061: }
6062: return(-1);
6063: }
1.1 root 6064: }
6065: if(param->env_seg == 0) {
6066: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
6067: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
6068: } else {
6069: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
6070: }
6071: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
6072:
6073: // check exe header
6074: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 6075: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 6076: UINT16 cs, ss, ip, sp;
6077:
6078: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6079: // memory allocation
6080: int header_size = header->header_size * 16;
6081: int load_size = header->pages * 512 - header_size;
6082: if(header_size + load_size < 512) {
6083: load_size = 512 - header_size;
6084: }
6085: paragraphs = (PSP_SIZE + load_size) >> 4;
6086: if(paragraphs + header->min_alloc > free_paragraphs) {
6087: msdos_mem_free(env_seg);
6088: return(-1);
6089: }
6090: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
6091: if(paragraphs > free_paragraphs) {
6092: paragraphs = free_paragraphs;
6093: }
1.1.1.8 root 6094: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6095: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6096: if(umb_linked != 0) {
6097: msdos_mem_link_umb();
6098: }
6099: msdos_mem_free(env_seg);
6100: return(-1);
6101: }
1.1 root 6102: }
6103: // relocation
6104: int start_seg = psp_seg + (PSP_SIZE >> 4);
6105: for(int i = 0; i < header->relocations; i++) {
6106: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6107: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6108: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6109: }
6110: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
6111: // segments
6112: cs = header->init_cs + start_seg;
6113: ss = header->init_ss + start_seg;
6114: ip = header->init_ip;
6115: sp = header->init_sp - 2; // for symdeb
6116: } else {
6117: // memory allocation
6118: paragraphs = free_paragraphs;
1.1.1.8 root 6119: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6120: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6121: if(umb_linked != 0) {
6122: msdos_mem_link_umb();
6123: }
6124: msdos_mem_free(env_seg);
6125: return(-1);
6126: }
1.1 root 6127: }
6128: int start_seg = psp_seg + (PSP_SIZE >> 4);
6129: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
6130: // segments
6131: cs = ss = psp_seg;
6132: ip = 0x100;
6133: sp = 0xfffe;
6134: }
1.1.1.29 root 6135: if(umb_linked != 0) {
6136: msdos_mem_link_umb();
6137: }
1.1 root 6138:
6139: // create psp
1.1.1.3 root 6140: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
6141: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 6142: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
6143: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
6144: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
6145: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
6146:
6147: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
6148: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
6149: mcb_psp->psp = mcb_env->psp = psp_seg;
6150:
1.1.1.4 root 6151: for(int i = 0; i < 8; i++) {
6152: if(name_tmp[i] == '.') {
6153: mcb_psp->prog_name[i] = '\0';
6154: break;
6155: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
6156: mcb_psp->prog_name[i] = name_tmp[i];
6157: i++;
6158: mcb_psp->prog_name[i] = name_tmp[i];
6159: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
6160: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
6161: } else {
6162: mcb_psp->prog_name[i] = name_tmp[i];
6163: }
6164: }
6165:
1.1 root 6166: // process info
6167: process_t *process = msdos_process_info_create(psp_seg);
6168: strcpy(process->module_dir, msdos_short_full_dir(path));
1.1.1.33 root 6169: #ifdef USE_DEBUGGER
6170: strcpy(process->module_path, path);
6171: #endif
1.1 root 6172: process->dta.w.l = 0x80;
6173: process->dta.w.h = psp_seg;
6174: process->switchar = '/';
6175: process->max_files = 20;
6176: process->parent_int_10h_feh_called = int_10h_feh_called;
6177: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 6178: process->parent_ds = SREG(DS);
1.1.1.31 root 6179: process->parent_es = SREG(ES);
1.1 root 6180:
6181: current_psp = psp_seg;
1.1.1.23 root 6182: msdos_sda_update(current_psp);
1.1 root 6183:
6184: if(al == 0x00) {
6185: int_10h_feh_called = int_10h_ffh_called = false;
6186:
1.1.1.38 root 6187: // pipe
6188: if(pipe_stdin_path[0] != '\0') {
6189: if((fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY)) != -1) {
6190: UINT16 info = msdos_drive_number(pipe_stdin_path);
6191: msdos_file_handler_open(fd, pipe_stdin_path, _isatty(fd), 0, info, current_psp);
6192: psp->file_table[0] = fd;
6193: msdos_psp_set_file_table(fd, fd, current_psp);
6194: }
6195: }
6196: if(pipe_stdout_path[0] != '\0') {
6197: if(_access(pipe_stdout_path, 0) == 0) {
6198: SetFileAttributes(pipe_stdout_path, FILE_ATTRIBUTE_NORMAL);
6199: DeleteFile(pipe_stdout_path);
6200: }
6201: if((fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT)) != -1) {
6202: UINT16 info = msdos_drive_number(pipe_stdout_path);
6203: msdos_file_handler_open(fd, pipe_stdout_path, _isatty(fd), 1, info, current_psp);
6204: psp->file_table[1] = fd;
6205: msdos_psp_set_file_table(fd, fd, current_psp);
6206: }
6207: }
1.1.1.39 root 6208: if(pipe_stderr_path[0] != '\0') {
6209: if(_access(pipe_stderr_path, 0) == 0) {
6210: SetFileAttributes(pipe_stderr_path, FILE_ATTRIBUTE_NORMAL);
6211: DeleteFile(pipe_stderr_path);
6212: }
6213: if((fd = _open(pipe_stderr_path, _O_WRONLY | _O_BINARY | _O_CREAT)) != -1) {
6214: UINT16 info = msdos_drive_number(pipe_stderr_path);
6215: msdos_file_handler_open(fd, pipe_stderr_path, _isatty(fd), 2, info, current_psp);
6216: psp->file_table[2] = fd;
6217: msdos_psp_set_file_table(fd, fd, current_psp);
6218: }
6219: }
1.1.1.38 root 6220:
1.1 root 6221: // registers and segments
6222: REG16(AX) = REG16(BX) = 0x00;
6223: REG16(CX) = 0xff;
6224: REG16(DX) = psp_seg;
6225: REG16(SI) = ip;
6226: REG16(DI) = sp;
6227: REG16(SP) = sp;
1.1.1.3 root 6228: SREG(DS) = SREG(ES) = psp_seg;
6229: SREG(SS) = ss;
6230: i386_load_segment_descriptor(DS);
6231: i386_load_segment_descriptor(ES);
6232: i386_load_segment_descriptor(SS);
1.1 root 6233:
6234: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
6235: i386_jmp_far(cs, ip);
6236: } else if(al == 0x01) {
6237: // copy ss:sp and cs:ip to param block
6238: param->sp = sp;
6239: param->ss = ss;
6240: param->ip = ip;
6241: param->cs = cs;
1.1.1.31 root 6242:
6243: // the AX value to be passed to the child program is put on top of the child's stack
6244: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 6245: }
6246: return(0);
6247: }
6248:
6249: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
6250: {
6251: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6252:
6253: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
6254: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
6255: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
6256:
1.1.1.3 root 6257: SREG(SS) = psp->stack.w.h;
6258: i386_load_segment_descriptor(SS);
1.1 root 6259: REG16(SP) = psp->stack.w.l;
6260: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
6261:
1.1.1.28 root 6262: // process_t *current_process = msdos_process_info_get(psp_seg);
6263: process_t *current_process = NULL;
6264: for(int i = 0; i < MAX_PROCESS; i++) {
6265: if(process[i].psp == psp_seg) {
6266: current_process = &process[i];
6267: break;
6268: }
6269: }
6270: if(current_process == NULL) {
6271: throw(0x1f); // general failure
6272: }
6273: int_10h_feh_called = current_process->parent_int_10h_feh_called;
6274: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
6275: if(current_process->called_by_int2eh) {
6276: REG16(AX) = ret;
6277: }
6278: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 6279: SREG(ES) = current_process->parent_es;
1.1.1.14 root 6280: i386_load_segment_descriptor(DS);
1.1.1.31 root 6281: i386_load_segment_descriptor(ES);
1.1 root 6282:
6283: if(mem_free) {
1.1.1.8 root 6284: int mcb_seg;
6285: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
6286: msdos_mem_free(mcb_seg + 1);
6287: }
6288: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
6289: msdos_mem_free(mcb_seg + 1);
6290: }
1.1 root 6291:
6292: for(int i = 0; i < MAX_FILES; i++) {
6293: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
6294: _close(i);
1.1.1.20 root 6295: msdos_file_handler_close(i);
6296: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 6297: }
6298: }
1.1.1.13 root 6299: msdos_dta_info_free(psp_seg);
1.1 root 6300: }
1.1.1.14 root 6301: msdos_stdio_reopen();
1.1 root 6302:
1.1.1.28 root 6303: memset(current_process, 0, sizeof(process_t));
1.1 root 6304:
6305: current_psp = psp->parent_psp;
6306: retval = ret;
1.1.1.23 root 6307: msdos_sda_update(current_psp);
1.1 root 6308: }
6309:
6310: // drive
6311:
1.1.1.42 root 6312: int pcbios_update_drive_param(int drive_num, int force_update);
6313:
1.1 root 6314: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
6315: {
1.1.1.41 root 6316: if(!(drive_num >= 0 && drive_num < 26)) {
6317: return(0);
6318: }
1.1.1.42 root 6319: pcbios_update_drive_param(drive_num, force_update);
6320:
6321: drive_param_t *drive_param = &drive_params[drive_num];
1.1 root 6322: *seg = DPB_TOP >> 4;
6323: *ofs = sizeof(dpb_t) * drive_num;
6324: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
6325:
6326: memset(dpb, 0, sizeof(dpb_t));
6327:
1.1.1.41 root 6328: dpb->drive_num = drive_num;
6329: dpb->unit_num = drive_num;
1.1.1.42 root 6330:
6331: if(drive_param->valid) {
6332: DISK_GEOMETRY *geo = &drive_param->geometry;
6333:
6334: dpb->bytes_per_sector = (UINT16)geo->BytesPerSector;
6335: dpb->highest_sector_num = (UINT8)(geo->SectorsPerTrack - 1);
6336: dpb->highest_cluster_num = (UINT16)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6337: dpb->maximum_cluster_num = (UINT32)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1);
6338: switch(geo->MediaType) {
6339: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6340: dpb->media_type = 0xff;
6341: break;
6342: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6343: dpb->media_type = 0xfe;
6344: break;
6345: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6346: dpb->media_type = 0xfd;
6347: break;
6348: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6349: dpb->media_type = 0xfc;
6350: break;
6351: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6352: case F3_1Pt2_512:
6353: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6354: case F5_720_512:
6355: dpb->media_type = 0xf9;
6356: break;
6357: case FixedMedia: // hard disk
6358: case RemovableMedia:
6359: case Unknown:
6360: dpb->media_type = 0xf8;
6361: break;
6362: default:
6363: dpb->media_type = 0xf0;
6364: break;
6365: }
6366: }
1.1.1.41 root 6367: dpb->next_dpb_ofs = (drive_num == 25) ? 0xffff : *ofs + sizeof(dpb_t);
6368: dpb->next_dpb_seg = (drive_num == 25) ? 0xffff : *seg;
1.1.1.42 root 6369: dpb->info_sector = 0xffff;
6370: dpb->backup_boot_sector = 0xffff;
6371: dpb->free_clusters = 0xffff;
6372: dpb->free_search_cluster = 0xffffffff;
6373:
6374: return(drive_param->valid);
1.1 root 6375: }
6376:
6377: // pc bios
6378:
1.1.1.35 root 6379: #ifdef USE_SERVICE_THREAD
6380: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress)
6381: {
6382: #if defined(HAS_I386)
6383: if(m_SF != 0) {
6384: m_SF = 0;
6385: mem[0xfffd0 + 0x15] = 0x79; // jns -4
6386: } else {
6387: m_SF = 1;
6388: mem[0xfffd0 + 0x15] = 0x78; // js -4
6389: }
6390: #else
6391: if(m_SignVal < 0) {
6392: m_SignVal = 0;
6393: mem[0xfffd0 + 0x15] = 0x79; // jns -4
6394: } else {
6395: m_SignVal = -1;
6396: mem[0xfffd0 + 0x15] = 0x78; // js -4
6397: }
6398: #endif
6399: i386_call_far(0xfffd, 0x0013);
6400: in_service = true;
6401: service_exit = false;
6402: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL));
6403: }
6404:
6405: void finish_service_loop()
6406: {
6407: if(in_service && service_exit) {
6408: #if defined(HAS_I386)
6409: if(m_SF != 0) {
6410: m_SF = 0;
6411: } else {
6412: m_SF = 1;
6413: }
6414: #else
6415: if(m_SignVal < 0) {
6416: m_SignVal = 0;
6417: } else {
6418: m_SignVal = -1;
6419: }
6420: #endif
6421: in_service = false;
6422: }
6423: }
6424: #endif
6425:
1.1.1.19 root 6426: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
6427: {
6428: static unsigned __int64 start_msec_since_midnight = 0;
6429: static unsigned __int64 start_msec_since_hostboot = 0;
6430:
6431: if(start_msec_since_midnight == 0) {
6432: SYSTEMTIME time;
6433: GetLocalTime(&time);
6434: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
6435: start_msec_since_hostboot = cur_msec;
6436: }
6437: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
6438: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
6439: return (UINT32)tick;
6440: }
6441:
6442: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
6443: {
6444: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
6445: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
6446:
6447: if(prev_tick > next_tick) {
6448: mem[0x470] = 1;
6449: }
6450: *(UINT32 *)(mem + 0x46c) = next_tick;
6451: }
6452:
1.1.1.14 root 6453: inline void pcbios_irq0()
6454: {
6455: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 6456: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 6457: }
6458:
1.1.1.16 root 6459: int pcbios_get_text_vram_address(int page)
1.1 root 6460: {
6461: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6462: return TEXT_VRAM_TOP;
1.1 root 6463: } else {
1.1.1.14 root 6464: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 6465: }
6466: }
6467:
1.1.1.16 root 6468: int pcbios_get_shadow_buffer_address(int page)
1.1 root 6469: {
1.1.1.14 root 6470: if(!int_10h_feh_called) {
1.1.1.16 root 6471: return pcbios_get_text_vram_address(page);
1.1.1.14 root 6472: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6473: return SHADOW_BUF_TOP;
6474: } else {
1.1.1.14 root 6475: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 6476: }
6477: }
6478:
1.1.1.16 root 6479: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 6480: {
1.1.1.16 root 6481: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 6482: }
6483:
1.1.1.16 root 6484: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 6485: {
1.1.1.14 root 6486: // clear the existing screen, not just the new one
6487: int clr_height = max(height, scr_height);
6488:
1.1.1.16 root 6489: if(scr_width != width || scr_height != height) {
6490: change_console_size(width, height);
1.1.1.14 root 6491: }
6492: mem[0x462] = 0;
6493: *(UINT16 *)(mem + 0x44e) = 0;
6494:
1.1.1.16 root 6495: text_vram_top_address = pcbios_get_text_vram_address(0);
6496: text_vram_end_address = text_vram_top_address + width * height * 2;
6497: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
6498: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 6499:
1.1.1.23 root 6500: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 6501: if(clr_screen) {
1.1.1.14 root 6502: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
6503: mem[ofs++] = 0x20;
6504: mem[ofs++] = 0x07;
6505: }
6506:
1.1.1.35 root 6507: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6508: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6509: #endif
1.1.1.14 root 6510: for(int y = 0; y < clr_height; y++) {
6511: for(int x = 0; x < scr_width; x++) {
6512: SCR_BUF(y,x).Char.AsciiChar = ' ';
6513: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 6514: }
6515: }
6516: SMALL_RECT rect;
1.1.1.14 root 6517: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
6518: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6519: vram_length_char = vram_last_length_char = 0;
6520: vram_length_attr = vram_last_length_attr = 0;
1.1.1.35 root 6521: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6522: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6523: #endif
1.1 root 6524: }
1.1.1.14 root 6525: COORD co;
6526: co.X = 0;
6527: co.Y = scr_top;
6528: SetConsoleCursorPosition(hStdout, co);
6529: cursor_moved = true;
6530: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 6531: }
6532:
1.1.1.36 root 6533: void pcbios_update_cursor_position()
6534: {
6535: CONSOLE_SCREEN_BUFFER_INFO csbi;
6536: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
6537: if(!restore_console_on_exit) {
6538: scr_top = csbi.srWindow.Top;
6539: }
6540: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
6541: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
6542: }
6543:
1.1.1.16 root 6544: inline void pcbios_int_10h_00h()
6545: {
6546: switch(REG8(AL) & 0x7f) {
6547: case 0x70: // v-text mode
6548: case 0x71: // extended cga v-text mode
6549: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
6550: break;
6551: default:
6552: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
6553: break;
6554: }
6555: if(REG8(AL) & 0x80) {
6556: mem[0x487] |= 0x80;
6557: } else {
6558: mem[0x487] &= ~0x80;
6559: }
6560: mem[0x449] = REG8(AL) & 0x7f;
6561: }
6562:
1.1 root 6563: inline void pcbios_int_10h_01h()
6564: {
1.1.1.13 root 6565: mem[0x460] = REG8(CL);
6566: mem[0x461] = REG8(CH);
1.1.1.14 root 6567:
1.1.1.23 root 6568: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6569: CONSOLE_CURSOR_INFO ci;
6570: GetConsoleCursorInfo(hStdout, &ci);
6571: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
6572: // if(ci.bVisible) {
6573: int lines = max(8, REG8(CL) + 1);
6574: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
6575: // }
6576: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 6577: }
6578:
6579: inline void pcbios_int_10h_02h()
6580: {
1.1.1.14 root 6581: // continuously setting the cursor effectively stops it blinking
6582: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 6583: COORD co;
6584: co.X = REG8(DL);
1.1.1.14 root 6585: co.Y = REG8(DH) + scr_top;
6586:
6587: // some programs hide the cursor by moving it off screen
6588: static bool hidden = false;
1.1.1.23 root 6589: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6590: CONSOLE_CURSOR_INFO ci;
6591: GetConsoleCursorInfo(hStdout, &ci);
6592:
6593: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
6594: if(ci.bVisible) {
6595: ci.bVisible = FALSE;
6596: // SetConsoleCursorInfo(hStdout, &ci);
6597: hidden = true;
6598: }
6599: } else if(hidden) {
6600: if(!ci.bVisible) {
6601: ci.bVisible = TRUE;
6602: // SetConsoleCursorInfo(hStdout, &ci);
6603: }
6604: hidden = false;
6605: }
1.1 root 6606: }
1.1.1.14 root 6607: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
6608: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 6609: }
6610:
6611: inline void pcbios_int_10h_03h()
6612: {
1.1.1.14 root 6613: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6614: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6615: REG8(CL) = mem[0x460];
6616: REG8(CH) = mem[0x461];
6617: }
6618:
6619: inline void pcbios_int_10h_05h()
6620: {
1.1.1.14 root 6621: if(REG8(AL) >= vram_pages) {
6622: return;
6623: }
6624: if(mem[0x462] != REG8(AL)) {
6625: vram_flush();
6626:
1.1.1.23 root 6627: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6628: SMALL_RECT rect;
1.1.1.14 root 6629: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6630: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6631:
1.1.1.16 root 6632: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 6633: for(int x = 0; x < scr_width; x++) {
6634: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6635: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6636: }
6637: }
1.1.1.16 root 6638: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 6639: for(int x = 0; x < scr_width; x++) {
6640: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
6641: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 6642: }
6643: }
1.1.1.14 root 6644: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6645:
6646: COORD co;
1.1.1.14 root 6647: co.X = mem[0x450 + REG8(AL) * 2];
6648: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
6649: if(co.Y < scr_top + scr_height) {
6650: SetConsoleCursorPosition(hStdout, co);
6651: }
1.1 root 6652: }
1.1.1.14 root 6653: mem[0x462] = REG8(AL);
6654: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
6655: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 6656: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 6657: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 6658: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 6659: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 6660: }
6661:
6662: inline void pcbios_int_10h_06h()
6663: {
1.1.1.14 root 6664: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6665: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6666: return;
6667: }
6668: vram_flush();
6669:
1.1.1.23 root 6670: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6671: SMALL_RECT rect;
1.1.1.14 root 6672: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6673: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6674:
6675: int right = min(REG8(DL), scr_width - 1);
6676: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6677:
6678: if(REG8(AL) == 0) {
1.1.1.14 root 6679: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6680: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6681: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6682: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6683: }
6684: }
6685: } else {
1.1.1.14 root 6686: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 6687: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6688: if(y2 <= bottom) {
6689: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6690: } else {
1.1.1.14 root 6691: SCR_BUF(y,x).Char.AsciiChar = ' ';
6692: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6693: }
1.1.1.14 root 6694: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6695: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6696: }
6697: }
6698: }
1.1.1.14 root 6699: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6700: }
6701:
6702: inline void pcbios_int_10h_07h()
6703: {
1.1.1.14 root 6704: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6705: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6706: return;
6707: }
6708: vram_flush();
6709:
1.1.1.23 root 6710: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6711: SMALL_RECT rect;
1.1.1.14 root 6712: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6713: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6714:
6715: int right = min(REG8(DL), scr_width - 1);
6716: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6717:
6718: if(REG8(AL) == 0) {
1.1.1.14 root 6719: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6720: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6721: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6722: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6723: }
6724: }
6725: } else {
1.1.1.14 root 6726: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 6727: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6728: if(y2 >= REG8(CH)) {
6729: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6730: } else {
1.1.1.14 root 6731: SCR_BUF(y,x).Char.AsciiChar = ' ';
6732: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6733: }
1.1.1.14 root 6734: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6735: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6736: }
6737: }
6738: }
1.1.1.14 root 6739: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6740: }
6741:
6742: inline void pcbios_int_10h_08h()
6743: {
6744: COORD co;
6745: DWORD num;
6746:
1.1.1.14 root 6747: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6748: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6749:
6750: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6751: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6752: co.Y += scr_top;
6753: vram_flush();
1.1 root 6754: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
6755: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
6756: REG8(AL) = scr_char[0];
6757: REG8(AH) = scr_attr[0];
6758: } else {
1.1.1.16 root 6759: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 6760: }
6761: }
6762:
6763: inline void pcbios_int_10h_09h()
6764: {
6765: COORD co;
6766:
1.1.1.14 root 6767: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6768: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6769:
1.1.1.16 root 6770: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6771: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6772:
6773: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6774: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6775: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6776: #endif
1.1.1.16 root 6777: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6778: while(dest < end) {
6779: write_text_vram_char(dest - vram, REG8(AL));
6780: mem[dest++] = REG8(AL);
6781: write_text_vram_attr(dest - vram, REG8(BL));
6782: mem[dest++] = REG8(BL);
1.1 root 6783: }
1.1.1.35 root 6784: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6785: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6786: #endif
1.1 root 6787: } else {
1.1.1.14 root 6788: while(dest < end) {
1.1 root 6789: mem[dest++] = REG8(AL);
6790: mem[dest++] = REG8(BL);
6791: }
6792: }
6793: }
6794:
6795: inline void pcbios_int_10h_0ah()
6796: {
6797: COORD co;
6798:
1.1.1.14 root 6799: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6800: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6801:
1.1.1.16 root 6802: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6803: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6804:
6805: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6806: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6807: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6808: #endif
1.1.1.16 root 6809: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6810: while(dest < end) {
6811: write_text_vram_char(dest - vram, REG8(AL));
6812: mem[dest++] = REG8(AL);
6813: dest++;
1.1 root 6814: }
1.1.1.35 root 6815: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6816: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6817: #endif
1.1 root 6818: } else {
1.1.1.14 root 6819: while(dest < end) {
1.1 root 6820: mem[dest++] = REG8(AL);
6821: dest++;
6822: }
6823: }
6824: }
6825:
1.1.1.40 root 6826: HDC get_console_window_device_context()
6827: {
6828: static HWND hwndFound = 0;
6829:
6830: if(hwndFound == 0) {
6831: // https://support.microsoft.com/en-us/help/124103/how-to-obtain-a-console-window-handle-hwnd
6832: char pszNewWindowTitle[1024];
6833: char pszOldWindowTitle[1024];
6834:
6835: GetConsoleTitle(pszOldWindowTitle, 1024);
6836: wsprintf(pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId());
6837: SetConsoleTitle(pszNewWindowTitle);
6838: Sleep(100);
6839: hwndFound = FindWindow(NULL, pszNewWindowTitle);
6840: SetConsoleTitle(pszOldWindowTitle);
6841: }
6842: return GetDC(hwndFound);
6843: }
6844:
6845: inline void pcbios_int_10h_0ch()
6846: {
6847: HDC hdc = get_console_window_device_context();
6848:
6849: if(hdc != NULL) {
6850: BYTE r = (REG8(AL) & 2) ? 255 : 0;
6851: BYTE g = (REG8(AL) & 4) ? 255 : 0;
6852: BYTE b = (REG8(AL) & 1) ? 255 : 0;
6853:
6854: if(REG8(AL) & 0x80) {
6855: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
6856: if(color != CLR_INVALID) {
6857: r ^= ((DWORD)color & 0x0000ff) ? 255 : 0;
6858: g ^= ((DWORD)color & 0x00ff00) ? 255 : 0;
6859: b ^= ((DWORD)color & 0xff0000) ? 255 : 0;
6860: }
6861: }
6862: SetPixel(hdc, REG16(CX), REG16(DX), RGB(r, g, b));
6863: }
6864: }
6865:
6866: inline void pcbios_int_10h_0dh()
6867: {
6868: HDC hdc = get_console_window_device_context();
6869: BYTE r = 0;
6870: BYTE g = 0;
6871: BYTE b = 0;
6872:
6873: if(hdc != NULL) {
6874: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
6875: if(color != CLR_INVALID) {
6876: r = ((DWORD)color & 0x0000ff) ? 255 : 0;
6877: g = ((DWORD)color & 0x00ff00) ? 255 : 0;
6878: b = ((DWORD)color & 0xff0000) ? 255 : 0;
6879: }
6880: }
6881: REG8(AL) = ((b != 0) ? 1 : 0) | ((r != 0) ? 2 : 0) | ((g != 0) ? 4 : 0);
6882: }
6883:
1.1 root 6884: inline void pcbios_int_10h_0eh()
6885: {
1.1.1.14 root 6886: DWORD num;
6887: COORD co;
6888:
6889: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6890: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6891:
6892: if(REG8(AL) == 7) {
6893: //MessageBeep(-1);
6894: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
6895: if(REG8(AL) == 10) {
6896: vram_flush();
6897: }
1.1.1.23 root 6898: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 6899: cursor_moved = true;
6900: } else {
1.1.1.16 root 6901: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 6902: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6903: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6904: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6905: #endif
1.1.1.16 root 6906: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6907: write_text_vram_char(dest - vram, REG8(AL));
1.1.1.35 root 6908: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6909: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6910: #endif
1.1.1.14 root 6911:
1.1.1.23 root 6912: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6913: if(++co.X == scr_width) {
6914: co.X = 0;
6915: if(++co.Y == scr_height) {
6916: vram_flush();
6917: WriteConsole(hStdout, "\n", 1, &num, NULL);
6918: cursor_moved = true;
6919: }
6920: }
6921: if(!cursor_moved) {
6922: co.Y += scr_top;
6923: SetConsoleCursorPosition(hStdout, co);
6924: cursor_moved = true;
6925: }
6926: }
6927: mem[dest] = REG8(AL);
6928: }
1.1 root 6929: }
6930:
6931: inline void pcbios_int_10h_0fh()
6932: {
6933: REG8(AL) = mem[0x449];
6934: REG8(AH) = mem[0x44a];
6935: REG8(BH) = mem[0x462];
6936: }
6937:
1.1.1.14 root 6938: inline void pcbios_int_10h_11h()
6939: {
6940: switch(REG8(AL)) {
1.1.1.16 root 6941: case 0x01:
1.1.1.14 root 6942: case 0x11:
1.1.1.16 root 6943: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 6944: break;
1.1.1.16 root 6945: case 0x02:
1.1.1.14 root 6946: case 0x12:
1.1.1.16 root 6947: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6948: break;
1.1.1.16 root 6949: case 0x04:
1.1.1.14 root 6950: case 0x14:
1.1.1.16 root 6951: pcbios_set_console_size(80, 25, true);
6952: break;
6953: case 0x18:
6954: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6955: break;
6956: case 0x30:
6957: SREG(ES) = 0;
6958: i386_load_segment_descriptor(ES);
6959: REG16(BP) = 0;
6960: REG16(CX) = mem[0x485];
6961: REG8(DL) = mem[0x484];
6962: break;
6963: }
6964: }
6965:
6966: inline void pcbios_int_10h_12h()
6967: {
1.1.1.16 root 6968: switch(REG8(BL)) {
6969: case 0x10:
1.1.1.14 root 6970: REG16(BX) = 0x0003;
6971: REG16(CX) = 0x0009;
1.1.1.16 root 6972: break;
1.1.1.14 root 6973: }
6974: }
6975:
1.1 root 6976: inline void pcbios_int_10h_13h()
6977: {
1.1.1.3 root 6978: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 6979: COORD co;
6980: DWORD num;
6981:
6982: co.X = REG8(DL);
1.1.1.14 root 6983: co.Y = REG8(DH) + scr_top;
6984:
6985: vram_flush();
1.1 root 6986:
6987: switch(REG8(AL)) {
6988: case 0x00:
6989: case 0x01:
6990: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6991: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6992: CONSOLE_SCREEN_BUFFER_INFO csbi;
6993: GetConsoleScreenBufferInfo(hStdout, &csbi);
6994: SetConsoleCursorPosition(hStdout, co);
6995:
6996: if(csbi.wAttributes != REG8(BL)) {
6997: SetConsoleTextAttribute(hStdout, REG8(BL));
6998: }
1.1.1.14 root 6999: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
7000:
1.1 root 7001: if(csbi.wAttributes != REG8(BL)) {
7002: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7003: }
7004: if(REG8(AL) == 0x00) {
1.1.1.15 root 7005: if(!restore_console_on_exit) {
7006: GetConsoleScreenBufferInfo(hStdout, &csbi);
7007: scr_top = csbi.srWindow.Top;
7008: }
1.1.1.14 root 7009: co.X = mem[0x450 + REG8(BH) * 2];
7010: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 7011: SetConsoleCursorPosition(hStdout, co);
7012: } else {
7013: cursor_moved = true;
7014: }
7015: } else {
1.1.1.3 root 7016: m_CF = 1;
1.1 root 7017: }
7018: break;
7019: case 0x02:
7020: case 0x03:
7021: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7022: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7023: CONSOLE_SCREEN_BUFFER_INFO csbi;
7024: GetConsoleScreenBufferInfo(hStdout, &csbi);
7025: SetConsoleCursorPosition(hStdout, co);
7026:
7027: WORD wAttributes = csbi.wAttributes;
7028: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
7029: if(wAttributes != mem[ofs + 1]) {
7030: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
7031: wAttributes = mem[ofs + 1];
7032: }
1.1.1.14 root 7033: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 7034: }
7035: if(csbi.wAttributes != wAttributes) {
7036: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7037: }
7038: if(REG8(AL) == 0x02) {
1.1.1.14 root 7039: co.X = mem[0x450 + REG8(BH) * 2];
7040: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 7041: SetConsoleCursorPosition(hStdout, co);
7042: } else {
7043: cursor_moved = true;
7044: }
7045: } else {
1.1.1.3 root 7046: m_CF = 1;
1.1 root 7047: }
7048: break;
7049: case 0x10:
7050: case 0x11:
7051: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7052: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7053: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
7054: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
7055: for(int i = 0; i < num; i++) {
7056: mem[ofs++] = scr_char[i];
7057: mem[ofs++] = scr_attr[i];
7058: if(REG8(AL) == 0x11) {
7059: mem[ofs++] = 0;
7060: mem[ofs++] = 0;
7061: }
7062: }
7063: } else {
1.1.1.16 root 7064: 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 7065: mem[ofs++] = mem[src++];
7066: mem[ofs++] = mem[src++];
7067: if(REG8(AL) == 0x11) {
7068: mem[ofs++] = 0;
7069: mem[ofs++] = 0;
7070: }
1.1.1.14 root 7071: if(++co.X == scr_width) {
7072: if(++co.Y == scr_height) {
1.1 root 7073: break;
7074: }
7075: co.X = 0;
7076: }
7077: }
7078: }
7079: break;
7080: case 0x20:
7081: case 0x21:
7082: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7083: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 7084: int len = min(REG16(CX), scr_width * scr_height);
7085: for(int i = 0; i < len; i++) {
1.1 root 7086: scr_char[i] = mem[ofs++];
7087: scr_attr[i] = mem[ofs++];
7088: if(REG8(AL) == 0x21) {
7089: ofs += 2;
7090: }
7091: }
1.1.1.14 root 7092: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7093: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7094: } else {
1.1.1.16 root 7095: 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 7096: mem[dest++] = mem[ofs++];
7097: mem[dest++] = mem[ofs++];
7098: if(REG8(AL) == 0x21) {
7099: ofs += 2;
7100: }
1.1.1.14 root 7101: if(++co.X == scr_width) {
7102: if(++co.Y == scr_height) {
1.1 root 7103: break;
7104: }
7105: co.X = 0;
7106: }
7107: }
7108: }
7109: break;
7110: default:
1.1.1.22 root 7111: 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 7112: m_CF = 1;
1.1 root 7113: break;
7114: }
7115: }
7116:
1.1.1.30 root 7117: inline void pcbios_int_10h_18h()
7118: {
7119: switch(REG8(AL)) {
7120: case 0x00:
7121: case 0x01:
7122: // REG8(AL) = 0x86;
7123: REG8(AL) = 0x00;
7124: break;
7125: default:
7126: 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));
7127: m_CF = 1;
7128: break;
7129: }
7130: }
7131:
1.1.1.14 root 7132: inline void pcbios_int_10h_1ah()
7133: {
7134: switch(REG8(AL)) {
7135: case 0x00:
7136: REG8(AL) = 0x1a;
7137: REG8(BL) = 0x08;
7138: REG8(BH) = 0x00;
7139: break;
7140: default:
1.1.1.22 root 7141: 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 7142: m_CF = 1;
7143: break;
7144: }
7145: }
7146:
1.1 root 7147: inline void pcbios_int_10h_1dh()
7148: {
7149: switch(REG8(AL)) {
1.1.1.43! root 7150: case 0x00:
! 7151: // DOS/V Shift Status Line Control is not supported
! 7152: m_CF = 1;
! 7153: break;
1.1 root 7154: case 0x01:
7155: break;
7156: case 0x02:
7157: REG16(BX) = 0;
7158: break;
7159: default:
1.1.1.22 root 7160: 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));
7161: m_CF = 1;
7162: break;
7163: }
7164: }
7165:
7166: inline void pcbios_int_10h_4fh()
7167: {
7168: switch(REG8(AL)) {
7169: case 0x00:
7170: REG8(AH) = 0x02; // not supported
7171: break;
7172: case 0x01:
7173: case 0x02:
7174: case 0x03:
7175: case 0x04:
7176: case 0x05:
7177: case 0x06:
7178: case 0x07:
7179: case 0x08:
7180: case 0x09:
7181: case 0x0a:
7182: case 0x0b:
7183: case 0x0c:
7184: REG8(AH) = 0x01; // failed
7185: break;
7186: default:
7187: 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 7188: m_CF = 1;
1.1 root 7189: break;
7190: }
7191: }
7192:
7193: inline void pcbios_int_10h_82h()
7194: {
7195: static UINT8 mode = 0;
7196:
7197: switch(REG8(AL)) {
1.1.1.22 root 7198: case 0x00:
1.1 root 7199: if(REG8(BL) != 0xff) {
7200: mode = REG8(BL);
7201: }
7202: REG8(AL) = mode;
7203: break;
7204: default:
1.1.1.22 root 7205: 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 7206: m_CF = 1;
1.1 root 7207: break;
7208: }
7209: }
7210:
1.1.1.22 root 7211: inline void pcbios_int_10h_83h()
7212: {
7213: static UINT8 mode = 0;
7214:
7215: switch(REG8(AL)) {
7216: case 0x00:
7217: REG16(AX) = 0; // offset???
7218: SREG(ES) = (SHADOW_BUF_TOP >> 4);
7219: i386_load_segment_descriptor(ES);
7220: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
7221: break;
7222: default:
7223: 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));
7224: m_CF = 1;
7225: break;
7226: }
7227: }
7228:
7229: inline void pcbios_int_10h_90h()
7230: {
7231: REG8(AL) = mem[0x449];
7232: }
7233:
7234: inline void pcbios_int_10h_91h()
7235: {
7236: REG8(AL) = 0x04; // VGA
7237: }
7238:
7239: inline void pcbios_int_10h_efh()
7240: {
7241: REG16(DX) = 0xffff;
7242: }
7243:
1.1 root 7244: inline void pcbios_int_10h_feh()
7245: {
7246: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 7247: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 7248: i386_load_segment_descriptor(ES);
1.1.1.8 root 7249: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 7250: }
7251: int_10h_feh_called = true;
7252: }
7253:
7254: inline void pcbios_int_10h_ffh()
7255: {
7256: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 7257: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7258: COORD co;
7259: DWORD num;
7260:
1.1.1.14 root 7261: vram_flush();
7262:
7263: co.X = (REG16(DI) >> 1) % scr_width;
7264: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 7265: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
7266: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 7267: int len;
7268: for(len = 0; ofs < end; len++) {
7269: scr_char[len] = mem[ofs++];
7270: scr_attr[len] = mem[ofs++];
7271: }
7272: co.Y += scr_top;
7273: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7274: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7275: }
7276: int_10h_ffh_called = true;
7277: }
7278:
1.1.1.42 root 7279: int pcbios_update_drive_param(int drive_num, int force_update)
7280: {
7281: if(drive_num >= 0 && drive_num < 26) {
7282: drive_param_t *drive_param = &drive_params[drive_num];
7283:
7284: if(force_update || !drive_param->initialized) {
7285: drive_param->valid = 0;
7286: char dev[64];
7287: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7288:
7289: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7290: if(hFile != INVALID_HANDLE_VALUE) {
7291: DWORD dwSize;
7292: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &drive_param->geometry, sizeof(DISK_GEOMETRY), &dwSize, NULL)) {
7293: drive_param->valid = 1;
7294: }
7295: CloseHandle(hFile);
7296: }
7297: drive_param->initialized = 1;
7298: }
7299: return(drive_param->valid);
7300: }
7301: return(0);
7302: }
7303:
7304: inline void pcbios_int_13h_00h()
7305: {
7306: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7307:
7308: if(pcbios_update_drive_param(drive_num, 1)) {
7309: REG8(AH) = 0x00; // successful completion
7310: } else {
7311: if(REG8(DL) & 0x80) {
7312: REG8(AH) = 0x05; // reset failed (hard disk)
7313: } else {
7314: REG8(AH) = 0x80; // timeout (not ready)
7315: }
7316: m_CF = 1;
7317: }
7318: }
7319:
7320: inline void pcbios_int_13h_02h()
7321: {
7322: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7323:
7324: if(REG8(AL) == 0) {
7325: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7326: m_CF = 1;
7327: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7328: REG8(AH) = 0xff; // sense operation failed (hard disk)
7329: m_CF = 1;
7330: } else {
7331: drive_param_t *drive_param = &drive_params[drive_num];
7332: DISK_GEOMETRY *geo = &drive_param->geometry;
7333: char dev[64];
7334: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7335:
7336: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7337: if(hFile == INVALID_HANDLE_VALUE) {
7338: REG8(AH) = 0xff; // sense operation failed (hard disk)
7339: m_CF = 1;
7340: } else {
7341: UINT32 sector_num = REG8(AL);
7342: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7343: UINT32 head = REG8(DH);
7344: UINT32 sector = REG8(CL) & 0x3f;
7345: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7346: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7347: DWORD dwSize;
7348:
7349: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7350: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7351: // m_CF = 1;
7352: // } else
7353: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7354: REG8(AH) = 0x04; // sector not found/read error
7355: m_CF = 1;
7356: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7357: REG8(AH) = 0x04; // sector not found/read error
7358: m_CF = 1;
7359: } else {
7360: REG8(AH) = 0x00; // successful completion
7361: }
7362: CloseHandle(hFile);
7363: }
7364: }
7365: }
7366:
7367: inline void pcbios_int_13h_03h()
7368: {
7369: // this operation may cause serious damage for drives, so support only floppy disk...
7370: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7371:
7372: if(REG8(AL) == 0) {
7373: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7374: m_CF = 1;
7375: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7376: REG8(AH) = 0xff; // sense operation failed (hard disk)
7377: m_CF = 1;
7378: } else if(!drive_params[drive_num].is_fdd()) {
7379: REG8(AH) = 0xff; // sense operation failed (hard disk)
7380: m_CF = 1;
7381: } else {
7382: drive_param_t *drive_param = &drive_params[drive_num];
7383: DISK_GEOMETRY *geo = &drive_param->geometry;
7384: char dev[64];
7385: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7386:
7387: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7388: if(hFile == INVALID_HANDLE_VALUE) {
7389: REG8(AH) = 0xff; // sense operation failed (hard disk)
7390: m_CF = 1;
7391: } else {
7392: UINT32 sector_num = REG8(AL);
7393: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7394: UINT32 head = REG8(DH);
7395: UINT32 sector = REG8(CL) & 0x3f;
7396: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7397: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7398: DWORD dwSize;
7399:
7400: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7401: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7402: // m_CF = 1;
7403: // } else
7404: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7405: REG8(AH) = 0x04; // sector not found/read error
7406: m_CF = 1;
7407: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7408: REG8(AH) = 0x04; // sector not found/read error
7409: m_CF = 1;
7410: } else {
7411: REG8(AH) = 0x00; // successful completion
7412: }
7413: CloseHandle(hFile);
7414: }
7415: }
7416: }
7417:
7418: inline void pcbios_int_13h_04h()
7419: {
7420: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7421:
7422: if(REG8(AL) == 0) {
7423: REG8(AH) = 0x01; // invalid function in AH or invalid parameter
7424: m_CF = 1;
7425: } else if(!pcbios_update_drive_param(drive_num, 0)) {
7426: REG8(AH) = 0xff; // sense operation failed (hard disk)
7427: m_CF = 1;
7428: } else {
7429: drive_param_t *drive_param = &drive_params[drive_num];
7430: DISK_GEOMETRY *geo = &drive_param->geometry;
7431: char dev[64];
7432: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
7433:
7434: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7435: if(hFile == INVALID_HANDLE_VALUE) {
7436: REG8(AH) = 0xff; // sense operation failed (hard disk)
7437: m_CF = 1;
7438: } else {
7439: UINT32 sector_num = REG8(AL);
7440: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2);
7441: UINT32 head = REG8(DH);
7442: UINT32 sector = REG8(CL) & 0x3f;
7443: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1;
7444: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX);
7445: DWORD dwSize;
7446: UINT8 *tmp_buffer = (UINT8 *)malloc(sector_num * geo->BytesPerSector);
7447:
7448: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7449: // REG8(AH) = 0xff; // sense operation failed (hard disk)
7450: // m_CF = 1;
7451: // } else
7452: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7453: REG8(AH) = 0x04; // sector not found/read error
7454: m_CF = 1;
7455: } else if(ReadFile(hFile, tmp_buffer, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) {
7456: REG8(AH) = 0x04; // sector not found/read error
7457: m_CF = 1;
7458: } else if(memcmp(mem + buffer_addr, tmp_buffer, sector_num * geo->BytesPerSector) != 0) {
7459: REG8(AH) = 0x05; // data did not verify correctly (TI Professional PC)
7460: m_CF = 1;
7461: } else {
7462: REG8(AH) = 0x00; // successful completion
7463: }
7464: free(tmp_buffer);
7465: CloseHandle(hFile);
7466: }
7467: }
7468: }
7469:
7470: inline void pcbios_int_13h_08h()
7471: {
7472: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7473:
7474: if(pcbios_update_drive_param(drive_num, 1)) {
7475: drive_param_t *drive_param = &drive_params[drive_num];
7476: DISK_GEOMETRY *geo = &drive_param->geometry;
7477:
7478: REG16(AX) = 0x0000;
7479: switch(geo->MediaType) {
7480: case F5_360_512:
7481: case F5_320_512:
7482: case F5_320_1024:
7483: case F5_180_512:
7484: case F5_160_512:
7485: REG8(BL) = 0x01; // 320K/360K disk
7486: break;
7487: case F5_1Pt2_512:
7488: case F3_1Pt2_512:
7489: case F3_1Pt23_1024:
7490: case F5_1Pt23_1024:
7491: REG8(BL) = 0x02; // 1.2M disk
7492: break;
7493: case F3_720_512:
7494: case F3_640_512:
7495: case F5_640_512:
7496: case F5_720_512:
7497: REG8(BL) = 0x03; // 720K disk
7498: break;
7499: case F3_1Pt44_512:
7500: REG8(BL) = 0x04; // 1.44M disk
7501: break;
7502: case F3_2Pt88_512:
7503: REG8(BL) = 0x06; // 2.88M disk
7504: break;
7505: case RemovableMedia:
7506: REG8(BL) = 0x10; // ATAPI Removable Media Device
7507: break;
7508: default:
7509: REG8(BL) = 0x00; // unknown
7510: break;
7511: }
7512: if(REG8(DL) & 0x80) {
7513: switch(GetLogicalDrives() & 0x0c) {
7514: case 0x00: REG8(DL) = 0x00; break;
7515: case 0x04:
7516: case 0x08: REG8(DL) = 0x01; break;
7517: case 0x0c: REG8(DL) = 0x02; break;
7518: }
7519: } else {
7520: switch(GetLogicalDrives() & 0x03) {
7521: case 0x00: REG8(DL) = 0x00; break;
7522: case 0x01:
7523: case 0x02: REG8(DL) = 0x01; break;
7524: case 0x03: REG8(DL) = 0x02; break;
7525: }
7526: }
7527: REG8(DH) = drive_param->head_num();
7528: int cyl = (geo->Cylinders.QuadPart > 0x3ff) ? 0x3ff : geo->Cylinders.QuadPart;
7529: int sec = (geo->SectorsPerTrack > 0x3f) ? 0x3f : geo->SectorsPerTrack;
7530: REG8(CH) = cyl & 0xff;
7531: REG8(CL) = (sec & 0x3f) | ((cyl & 0x300) >> 2);
7532: } else {
7533: REG8(AH) = 0x07;
7534: m_CF = 1;
7535: }
7536: }
7537:
7538: inline void pcbios_int_13h_10h()
7539: {
7540: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7541:
7542: if(pcbios_update_drive_param(drive_num, 1)) {
7543: REG8(AH) = 0x00; // successful completion
7544: } else {
7545: if(REG8(DL) & 0x80) {
7546: REG8(AH) = 0xaa; // drive not ready (hard disk)
7547: } else {
7548: REG8(AH) = 0x80; // timeout (not ready)
7549: }
7550: m_CF = 1;
7551: }
7552: }
7553:
7554: inline void pcbios_int_13h_15h()
7555: {
7556: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1;
7557:
7558: if(pcbios_update_drive_param(drive_num, 1)) {
7559: if(REG8(DL) & 0x80) {
7560: REG8(AH) = 0x02; // floppy (or other removable drive) with change-line support
7561: } else {
7562: REG8(AH) = 0x03; // hard disk
7563: }
7564: } else {
7565: REG8(AH) = 0x00; // no such drive
7566: }
7567: }
7568:
1.1.1.43! root 7569: inline void pcbios_int_13h_41h()
! 7570: {
! 7571: if(REG16(BX) == 0x55aa) {
! 7572: // IBM/MS INT 13 Extensions is not installed
! 7573: REG8(AH) = 0x01;
! 7574: m_CF = 1;
! 7575: } else {
! 7576: 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));
! 7577: REG8(AH) = 0x01;
! 7578: m_CF = 1;
! 7579: }
! 7580: }
! 7581:
1.1.1.25 root 7582: inline void pcbios_int_14h_00h()
7583: {
1.1.1.29 root 7584: if(REG16(DX) < 4) {
1.1.1.25 root 7585: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
7586: UINT8 selector = sio_read(REG16(DX), 3);
7587: selector &= ~0x3f;
7588: selector |= REG8(AL) & 0x1f;
7589: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
7590: sio_write(REG16(DX), 3, selector | 0x80);
7591: sio_write(REG16(DX), 0, divisor & 0xff);
7592: sio_write(REG16(DX), 1, divisor >> 8);
7593: sio_write(REG16(DX), 3, selector);
7594: REG8(AH) = sio_read(REG16(DX), 5);
7595: REG8(AL) = sio_read(REG16(DX), 6);
7596: } else {
7597: REG8(AH) = 0x80;
7598: }
7599: }
7600:
7601: inline void pcbios_int_14h_01h()
7602: {
1.1.1.29 root 7603: if(REG16(DX) < 4) {
1.1.1.25 root 7604: UINT8 selector = sio_read(REG16(DX), 3);
7605: sio_write(REG16(DX), 3, selector & ~0x80);
7606: sio_write(REG16(DX), 0, REG8(AL));
7607: sio_write(REG16(DX), 3, selector);
7608: REG8(AH) = sio_read(REG16(DX), 5);
7609: } else {
7610: REG8(AH) = 0x80;
7611: }
7612: }
7613:
7614: inline void pcbios_int_14h_02h()
7615: {
1.1.1.29 root 7616: if(REG16(DX) < 4) {
1.1.1.25 root 7617: UINT8 selector = sio_read(REG16(DX), 3);
7618: sio_write(REG16(DX), 3, selector & ~0x80);
7619: REG8(AL) = sio_read(REG16(DX), 0);
7620: sio_write(REG16(DX), 3, selector);
7621: REG8(AH) = sio_read(REG16(DX), 5);
7622: } else {
7623: REG8(AH) = 0x80;
7624: }
7625: }
7626:
7627: inline void pcbios_int_14h_03h()
7628: {
1.1.1.29 root 7629: if(REG16(DX) < 4) {
1.1.1.25 root 7630: REG8(AH) = sio_read(REG16(DX), 5);
7631: REG8(AL) = sio_read(REG16(DX), 6);
7632: } else {
7633: REG8(AH) = 0x80;
7634: }
7635: }
7636:
7637: inline void pcbios_int_14h_04h()
7638: {
1.1.1.29 root 7639: if(REG16(DX) < 4) {
1.1.1.25 root 7640: UINT8 selector = sio_read(REG16(DX), 3);
7641: if(REG8(CH) <= 0x03) {
7642: selector = (selector & ~0x03) | REG8(CH);
7643: }
7644: if(REG8(BL) == 0x00) {
7645: selector &= ~0x04;
7646: } else if(REG8(BL) == 0x01) {
7647: selector |= 0x04;
7648: }
7649: if(REG8(BH) == 0x00) {
7650: selector = (selector & ~0x38) | 0x00;
7651: } else if(REG8(BH) == 0x01) {
7652: selector = (selector & ~0x38) | 0x08;
7653: } else if(REG8(BH) == 0x02) {
7654: selector = (selector & ~0x38) | 0x18;
7655: } else if(REG8(BH) == 0x03) {
7656: selector = (selector & ~0x38) | 0x28;
7657: } else if(REG8(BH) == 0x04) {
7658: selector = (selector & ~0x38) | 0x38;
7659: }
7660: if(REG8(AL) == 0x00) {
7661: selector |= 0x40;
7662: } else if(REG8(AL) == 0x01) {
7663: selector &= ~0x40;
7664: }
7665: if(REG8(CL) <= 0x0b) {
7666: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
7667: UINT16 divisor = 115200 / rate[REG8(CL)];
7668: sio_write(REG16(DX), 3, selector | 0x80);
7669: sio_write(REG16(DX), 0, divisor & 0xff);
7670: sio_write(REG16(DX), 1, divisor >> 8);
7671: }
7672: sio_write(REG16(DX), 3, selector);
7673: REG8(AH) = sio_read(REG16(DX), 5);
7674: REG8(AL) = sio_read(REG16(DX), 6);
7675: } else {
7676: REG8(AH) = 0x80;
7677: }
7678: }
7679:
7680: inline void pcbios_int_14h_05h()
7681: {
1.1.1.29 root 7682: if(REG16(DX) < 4) {
1.1.1.25 root 7683: if(REG8(AL) == 0x00) {
7684: REG8(BL) = sio_read(REG16(DX), 4);
7685: REG8(AH) = sio_read(REG16(DX), 5);
7686: REG8(AL) = sio_read(REG16(DX), 6);
7687: } else if(REG8(AL) == 0x01) {
7688: sio_write(REG16(DX), 4, REG8(BL));
7689: REG8(AH) = sio_read(REG16(DX), 5);
7690: REG8(AL) = sio_read(REG16(DX), 6);
7691: } else {
7692: 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));
7693: }
7694: } else {
7695: REG8(AH) = 0x80;
7696: }
7697: }
7698:
1.1.1.14 root 7699: inline void pcbios_int_15h_10h()
7700: {
1.1.1.22 root 7701: switch(REG8(AL)) {
7702: case 0x00:
1.1.1.14 root 7703: Sleep(10);
1.1.1.35 root 7704: REQUEST_HARDWRE_UPDATE();
1.1.1.22 root 7705: break;
7706: default:
7707: 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 7708: REG8(AH) = 0x86;
7709: m_CF = 1;
7710: }
7711: }
7712:
1.1 root 7713: inline void pcbios_int_15h_23h()
7714: {
7715: switch(REG8(AL)) {
1.1.1.22 root 7716: case 0x00:
1.1.1.8 root 7717: REG8(CL) = cmos_read(0x2d);
7718: REG8(CH) = cmos_read(0x2e);
1.1 root 7719: break;
1.1.1.22 root 7720: case 0x01:
1.1.1.8 root 7721: cmos_write(0x2d, REG8(CL));
7722: cmos_write(0x2e, REG8(CH));
1.1 root 7723: break;
7724: default:
1.1.1.22 root 7725: 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 7726: REG8(AH) = 0x86;
1.1.1.3 root 7727: m_CF = 1;
1.1 root 7728: break;
7729: }
7730: }
7731:
7732: inline void pcbios_int_15h_24h()
7733: {
7734: switch(REG8(AL)) {
1.1.1.22 root 7735: case 0x00:
1.1.1.3 root 7736: i386_set_a20_line(0);
1.1 root 7737: REG8(AH) = 0;
7738: break;
1.1.1.22 root 7739: case 0x01:
1.1.1.3 root 7740: i386_set_a20_line(1);
1.1 root 7741: REG8(AH) = 0;
7742: break;
1.1.1.22 root 7743: case 0x02:
1.1 root 7744: REG8(AH) = 0;
1.1.1.3 root 7745: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 7746: REG16(CX) = 0;
7747: break;
1.1.1.22 root 7748: case 0x03:
1.1 root 7749: REG16(AX) = 0;
7750: REG16(BX) = 0;
7751: break;
1.1.1.22 root 7752: default:
7753: 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));
7754: REG8(AH) = 0x86;
7755: m_CF = 1;
7756: break;
1.1 root 7757: }
7758: }
7759:
7760: inline void pcbios_int_15h_49h()
7761: {
1.1.1.27 root 7762: REG8(AH) = 0x00;
7763: REG8(BL) = 0x00; // DOS/V
1.1 root 7764: }
7765:
1.1.1.22 root 7766: inline void pcbios_int_15h_50h()
7767: {
7768: switch(REG8(AL)) {
7769: case 0x00:
7770: case 0x01:
7771: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
7772: REG8(AH) = 0x01; // invalid font type in bh
7773: m_CF = 1;
1.1.1.27 root 7774: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 7775: REG8(AH) = 0x02; // bl not zero
7776: m_CF = 1;
7777: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
7778: REG8(AH) = 0x04; // invalid code page
7779: m_CF = 1;
1.1.1.27 root 7780: } else if(REG8(AL) == 0x01) {
7781: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 7782: m_CF = 1;
1.1.1.27 root 7783: } else {
7784: // dummy font read routine is at fffd:000d
7785: SREG(ES) = 0xfffd;
7786: i386_load_segment_descriptor(ES);
1.1.1.32 root 7787: REG16(BX) = 0x000d;
1.1.1.27 root 7788: REG8(AH) = 0x00; // success
1.1.1.22 root 7789: }
7790: break;
7791: default:
7792: 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));
7793: REG8(AH) = 0x86;
7794: m_CF = 1;
7795: break;
7796: }
7797: }
7798:
1.1.1.30 root 7799: inline void pcbios_int_15h_53h()
7800: {
7801: switch(REG8(AL)) {
7802: case 0x00:
7803: // APM is not installed
7804: REG8(AH) = 0x86;
7805: m_CF = 1;
7806: break;
7807: default:
7808: 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));
7809: REG8(AH) = 0x86;
7810: m_CF = 1;
7811: break;
7812: }
7813: }
7814:
1.1.1.43! root 7815: inline void pcbios_int_15h_84h()
! 7816: {
! 7817: // joystick support (from DOSBox)
! 7818: switch(REG16(DX)) {
! 7819: case 0x00:
! 7820: REG16(AX) = 0x00f0;
! 7821: REG16(DX) = 0x0201;
! 7822: m_CF = 1;
! 7823: break;
! 7824: case 0x01:
! 7825: REG16(AX) = REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
! 7826: m_CF = 1;
! 7827: break;
! 7828: default:
! 7829: 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));
! 7830: REG8(AH) = 0x86;
! 7831: m_CF = 1;
! 7832: break;
! 7833: }
! 7834: }
1.1.1.35 root 7835:
7836: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID)
1.1 root 7837: {
7838: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 7839: UINT32 msec = usec / 1000;
7840:
1.1.1.35 root 7841: while(msec && !m_halted) {
1.1.1.14 root 7842: UINT32 tmp = min(msec, 100);
7843: if(msec - tmp < 10) {
7844: tmp = msec;
7845: }
7846: Sleep(tmp);
7847: msec -= tmp;
7848: }
1.1.1.35 root 7849:
7850: #ifdef USE_SERVICE_THREAD
7851: service_exit = true;
7852: #endif
7853: return(0);
7854: }
7855:
7856: inline void pcbios_int_15h_86h()
7857: {
7858: if(!(REG16(CX) == 0 && REG16(DX) == 0)) {
7859: #ifdef USE_SERVICE_THREAD
7860: start_service_loop(pcbios_int_15h_86h_thread);
7861: #else
7862: pcbios_int_15h_86h_thread(NULL);
7863: REQUEST_HARDWRE_UPDATE();
7864: #endif
7865: }
1.1 root 7866: }
7867:
7868: inline void pcbios_int_15h_87h()
7869: {
7870: // copy extended memory (from DOSBox)
7871: int len = REG16(CX) * 2;
1.1.1.3 root 7872: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 7873: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
7874: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
7875: memcpy(mem + dst, mem + src, len);
7876: REG16(AX) = 0x00;
7877: }
7878:
7879: inline void pcbios_int_15h_88h()
7880: {
1.1.1.17 root 7881: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 7882: }
7883:
7884: inline void pcbios_int_15h_89h()
7885: {
1.1.1.21 root 7886: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 7887: // switch to protected mode (from DOSBox)
7888: write_io_byte(0x20, 0x10);
7889: write_io_byte(0x21, REG8(BH));
7890: write_io_byte(0x21, 0x00);
7891: write_io_byte(0xa0, 0x10);
7892: write_io_byte(0xa1, REG8(BL));
7893: write_io_byte(0xa1, 0x00);
1.1.1.3 root 7894: i386_set_a20_line(1);
7895: int ofs = SREG_BASE(ES) + REG16(SI);
7896: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
7897: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
7898: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
7899: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
7900: #if defined(HAS_I386)
7901: m_cr[0] |= 1;
7902: #else
7903: m_msw |= 1;
7904: #endif
7905: SREG(DS) = 0x18;
7906: SREG(ES) = 0x20;
7907: SREG(SS) = 0x28;
7908: i386_load_segment_descriptor(DS);
7909: i386_load_segment_descriptor(ES);
7910: i386_load_segment_descriptor(SS);
1.1.1.21 root 7911: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 7912: REG16(SP) += 6;
1.1.1.3 root 7913: #if defined(HAS_I386)
1.1.1.21 root 7914: UINT32 flags = get_flags();
7915: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7916: set_flags(flags);
1.1.1.3 root 7917: #else
1.1.1.21 root 7918: UINT32 flags = CompressFlags();
7919: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7920: ExpandFlags(flags);
1.1.1.3 root 7921: #endif
1.1 root 7922: REG16(AX) = 0x00;
1.1.1.21 root 7923: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 7924: #else
1.1.1.21 root 7925: // i86/i186/v30: protected mode is not supported
1.1 root 7926: REG8(AH) = 0x86;
1.1.1.3 root 7927: m_CF = 1;
1.1 root 7928: #endif
7929: }
7930:
1.1.1.21 root 7931: inline void pcbios_int_15h_8ah()
7932: {
7933: UINT32 size = MAX_MEM - 0x100000;
7934: REG16(AX) = size & 0xffff;
7935: REG16(DX) = size >> 16;
7936: }
7937:
1.1.1.3 root 7938: #if defined(HAS_I386)
1.1 root 7939: inline void pcbios_int_15h_c9h()
7940: {
7941: REG8(AH) = 0x00;
7942: REG8(CH) = cpu_type;
7943: REG8(CL) = cpu_step;
7944: }
1.1.1.3 root 7945: #endif
1.1 root 7946:
7947: inline void pcbios_int_15h_cah()
7948: {
7949: switch(REG8(AL)) {
1.1.1.22 root 7950: case 0x00:
1.1 root 7951: if(REG8(BL) > 0x3f) {
7952: REG8(AH) = 0x03;
1.1.1.3 root 7953: m_CF = 1;
1.1 root 7954: } else if(REG8(BL) < 0x0e) {
7955: REG8(AH) = 0x04;
1.1.1.3 root 7956: m_CF = 1;
1.1 root 7957: } else {
1.1.1.8 root 7958: REG8(CL) = cmos_read(REG8(BL));
1.1 root 7959: }
7960: break;
1.1.1.22 root 7961: case 0x01:
1.1 root 7962: if(REG8(BL) > 0x3f) {
7963: REG8(AH) = 0x03;
1.1.1.3 root 7964: m_CF = 1;
1.1 root 7965: } else if(REG8(BL) < 0x0e) {
7966: REG8(AH) = 0x04;
1.1.1.3 root 7967: m_CF = 1;
1.1 root 7968: } else {
1.1.1.8 root 7969: cmos_write(REG8(BL), REG8(CL));
1.1 root 7970: }
7971: break;
7972: default:
1.1.1.22 root 7973: 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 7974: REG8(AH) = 0x86;
1.1.1.3 root 7975: m_CF = 1;
1.1 root 7976: break;
7977: }
7978: }
7979:
1.1.1.22 root 7980: inline void pcbios_int_15h_e8h()
1.1.1.17 root 7981: {
1.1.1.22 root 7982: switch(REG8(AL)) {
7983: #if defined(HAS_I386)
7984: case 0x01:
7985: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
7986: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
7987: break;
1.1.1.17 root 7988: #endif
1.1.1.22 root 7989: default:
7990: 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));
7991: REG8(AH) = 0x86;
7992: m_CF = 1;
7993: break;
7994: }
7995: }
1.1.1.17 root 7996:
1.1.1.33 root 7997: void pcbios_update_key_code(bool wait)
1.1 root 7998: {
1.1.1.32 root 7999: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8000: #ifdef USE_SERVICE_THREAD
8001: EnterCriticalSection(&key_buf_crit_sect);
8002: #endif
8003: bool empty = key_buf_char->empty();
8004: #ifdef USE_SERVICE_THREAD
8005: LeaveCriticalSection(&key_buf_crit_sect);
8006: #endif
8007: if(empty) {
1.1.1.32 root 8008: if(!update_key_buffer()) {
1.1.1.33 root 8009: if(wait) {
1.1.1.32 root 8010: Sleep(10);
8011: } else {
8012: maybe_idle();
8013: }
1.1.1.14 root 8014: }
8015: }
1.1.1.34 root 8016: }
8017: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8018: #ifdef USE_SERVICE_THREAD
8019: EnterCriticalSection(&key_buf_crit_sect);
8020: #endif
1.1.1.32 root 8021: if(key_buf_char->count() != 0) {
1.1.1.41 root 8022: int key_char = key_buf_char->read();
8023: int key_scan = key_buf_scan->read();
8024: key_code = key_char << 0;
8025: key_code |= key_scan << 8;
1.1.1.35 root 8026: key_recv = 0x0000ffff;
1.1.1.41 root 8027: // write to bottom of key buffer
8028: mem[0x43c] = (UINT8)key_char;
8029: mem[0x43d] = (UINT8)key_scan;
1.1.1.32 root 8030: }
8031: if(key_buf_char->count() != 0) {
1.1.1.41 root 8032: int key_char = key_buf_char->read();
8033: int key_scan = key_buf_scan->read();
8034: key_code |= key_char << 16;
8035: key_code |= key_scan << 24;
1.1.1.33 root 8036: key_recv |= 0xffff0000;
1.1.1.41 root 8037: // write to bottom of key buffer
8038: mem[0x43c] = (UINT8)key_char;
8039: mem[0x43d] = (UINT8)key_scan;
1.1.1.32 root 8040: }
1.1.1.35 root 8041: #ifdef USE_SERVICE_THREAD
8042: LeaveCriticalSection(&key_buf_crit_sect);
8043: #endif
1.1 root 8044: }
8045: }
8046:
1.1.1.35 root 8047: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID)
1.1 root 8048: {
1.1.1.33 root 8049: while(key_recv == 0 && !m_halted) {
8050: pcbios_update_key_code(true);
1.1 root 8051: }
1.1.1.33 root 8052: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
8053: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
8054: if(REG8(AH) == 0x10) {
8055: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
8056: } else {
8057: key_code = ((key_code >> 16) & 0xff00);
8058: }
8059: key_recv >>= 16;
1.1 root 8060: }
8061: }
8062: REG16(AX) = key_code & 0xffff;
8063: key_code >>= 16;
1.1.1.33 root 8064: key_recv >>= 16;
1.1.1.35 root 8065:
8066: #ifdef USE_SERVICE_THREAD
8067: service_exit = true;
8068: #endif
8069: return(0);
8070: }
8071:
8072: inline void pcbios_int_16h_00h()
8073: {
8074: #ifdef USE_SERVICE_THREAD
8075: start_service_loop(pcbios_int_16h_00h_thread);
8076: #else
8077: pcbios_int_16h_00h_thread(NULL);
8078: REQUEST_HARDWRE_UPDATE();
8079: #endif
1.1 root 8080: }
8081:
8082: inline void pcbios_int_16h_01h()
8083: {
1.1.1.33 root 8084: if(key_recv == 0) {
8085: pcbios_update_key_code(false);
1.1.1.5 root 8086: }
1.1.1.33 root 8087: if(key_recv != 0) {
8088: UINT32 key_code_tmp = key_code;
8089: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
8090: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
8091: if(REG8(AH) == 0x11) {
8092: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
8093: } else {
8094: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
8095: }
8096: }
1.1 root 8097: }
1.1.1.5 root 8098: REG16(AX) = key_code_tmp & 0xffff;
1.1.1.3 root 8099: #if defined(HAS_I386)
1.1.1.33 root 8100: m_ZF = 0;
8101: #else
8102: m_ZeroVal = 1;
8103: #endif
8104: } else {
8105: #if defined(HAS_I386)
8106: m_ZF = 1;
1.1.1.3 root 8107: #else
1.1.1.33 root 8108: m_ZeroVal = 0;
1.1.1.3 root 8109: #endif
1.1.1.33 root 8110: }
1.1 root 8111: }
8112:
8113: inline void pcbios_int_16h_02h()
8114: {
8115: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
8116: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
8117: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
8118: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
8119: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
8120: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
8121: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
8122: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
8123: }
8124:
8125: inline void pcbios_int_16h_03h()
8126: {
8127: static UINT16 status = 0;
8128:
8129: switch(REG8(AL)) {
8130: case 0x05:
8131: status = REG16(BX);
8132: break;
8133: case 0x06:
8134: REG16(BX) = status;
8135: break;
8136: default:
1.1.1.3 root 8137: m_CF = 1;
1.1 root 8138: break;
8139: }
8140: }
8141:
8142: inline void pcbios_int_16h_05h()
8143: {
1.1.1.32 root 8144: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 8145: #ifdef USE_SERVICE_THREAD
8146: EnterCriticalSection(&key_buf_crit_sect);
8147: #endif
1.1.1.32 root 8148: key_buf_char->write(REG8(CL));
8149: key_buf_scan->write(REG8(CH));
1.1.1.35 root 8150: #ifdef USE_SERVICE_THREAD
8151: LeaveCriticalSection(&key_buf_crit_sect);
8152: #endif
1.1.1.32 root 8153: }
1.1 root 8154: REG8(AL) = 0x00;
8155: }
8156:
8157: inline void pcbios_int_16h_12h()
8158: {
8159: pcbios_int_16h_02h();
8160:
8161: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
8162: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
8163: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
8164: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
8165: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
8166: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
8167: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
8168: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
8169: }
8170:
8171: inline void pcbios_int_16h_13h()
8172: {
8173: static UINT16 status = 0;
8174:
8175: switch(REG8(AL)) {
8176: case 0x00:
8177: status = REG16(DX);
8178: break;
8179: case 0x01:
8180: REG16(DX) = status;
8181: break;
8182: default:
1.1.1.22 root 8183: 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 8184: m_CF = 1;
1.1 root 8185: break;
8186: }
8187: }
8188:
8189: inline void pcbios_int_16h_14h()
8190: {
8191: static UINT8 status = 0;
8192:
8193: switch(REG8(AL)) {
8194: case 0x00:
8195: case 0x01:
8196: status = REG8(AL);
8197: break;
8198: case 0x02:
8199: REG8(AL) = status;
8200: break;
8201: default:
1.1.1.22 root 8202: 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 8203: m_CF = 1;
1.1 root 8204: break;
8205: }
8206: }
8207:
1.1.1.24 root 8208: inline void pcbios_int_16h_55h()
8209: {
8210: switch(REG8(AL)) {
8211: case 0x00:
8212: // keyboard tsr is not present
8213: break;
8214: case 0xfe:
8215: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
8216: break;
8217: case 0xff:
8218: break;
8219: default:
8220: 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));
8221: m_CF = 1;
8222: break;
8223: }
8224: }
8225:
1.1.1.30 root 8226: inline void pcbios_int_16h_6fh()
8227: {
8228: switch(REG8(AL)) {
8229: case 0x00:
8230: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
8231: break;
8232: default:
8233: 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));
8234: m_CF = 1;
8235: break;
8236: }
8237: }
8238:
1.1.1.37 root 8239: UINT16 pcbios_printer_jis2sjis(UINT16 jis)
8240: {
8241: UINT8 hi = jis >> 8;
8242: UINT8 lo = jis & 0xff;
8243:
8244: lo = (hi & 0x01) ? lo - 0x1f : lo + 0x7d;
8245: hi = (hi - 0x21) / 2 + 0x81;
8246: hi = (hi >= 0xa0) ? hi + 0x40 : hi;
8247: lo = (lo >= 0x7f) ? lo + 0x01 : lo;
8248:
8249: return((hi << 8) + lo);
8250: }
8251:
8252: UINT16 pcbios_printer_sjis2jis(UINT16 sjis)
8253: {
8254: UINT8 hi = sjis >> 8;
8255: UINT8 lo = sjis & 0xff;
8256:
8257: if(hi == 0x80 || (hi >= 0xeb && hi <= 0xef) || (hi >= 0xf4 && hi <= 0xff)) {
8258: return(0x2121);
8259: }
8260: if((lo >= 0x00 && lo <= 0x3f) || lo == 0x7f || (lo >= 0xfd && lo <= 0xff)) {
8261: return(0x2121);
8262: }
8263: if(hi >= 0xf0 && hi <= 0xf3) {
8264: // gaiji
8265: if(lo >= 0x40 && lo <= 0x7e) {
8266: return(0x7721 + lo - 0x40 + (hi - 0xf0) * 0x200);
8267: }
8268: if(lo >= 0x80 && lo <= 0x9e) {
8269: return(0x7760 + lo - 0x80 + (hi - 0xf0) * 0x200);
8270: }
8271: if(lo >= 0x9f && lo <= 0xfc) {
8272: return(0x7821 + lo - 0x9f + (hi - 0xf0) * 0x200);
8273: }
8274: }
8275: hi = (hi >= 0xe0) ? hi - 0x40 : hi;
8276: lo = (lo >= 0x80) ? lo - 0x01 : lo;
8277: hi = ((lo >= 0x9e) ? 1 : 0) + (hi - 0x81) * 2 + 0x21;
8278: lo = ((lo >= 0x9e) ? lo - 0x9e : lo - 0x40) + 0x21;
8279:
8280: return((hi << 8) + lo);
8281: }
8282:
1.1.1.38 root 8283: // AX�e�N�j�J�����t�@�����X�K�C�h 1989
8284: // �t�^10 ���{��g��PRINTER DRIVER NIOS�T�d�l
8285: // 6. �R���g���[���R�[�h�̉��
1.1.1.37 root 8286:
8287: void pcbios_printer_out(int c, UINT8 data)
8288: {
8289: if(pio[c].conv_mode) {
8290: if(pio[c].sjis_hi != 0) {
8291: if(!pio[c].jis_mode) {
8292: printer_out(c, 0x1c);
8293: printer_out(c, 0x26);
8294: pio[c].jis_mode = true;
8295: }
8296: UINT16 jis = pcbios_printer_sjis2jis((pio[c].sjis_hi << 8) | data);
8297: printer_out(c, jis >> 8);
8298: printer_out(c, jis & 0xff);
8299: pio[c].sjis_hi = 0;
8300: } else if(pio[c].esc_buf[0] == 0x1b) {
8301: printer_out(c, data);
8302: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
8303: pio[c].esc_buf[pio[c].esc_len] = data;
8304: }
8305: pio[c].esc_len++;
8306:
8307: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 8308: case 0x33: // 1Bh 33h XX
8309: case 0x4a: // 1Bh 4Ah XX
8310: case 0x4e: // 1Bh 4Eh XX
8311: case 0x51: // 1Bh 51h XX
8312: case 0x55: // 1Bh 55h XX
8313: case 0x6c: // 1Bh 6Ch XX
8314: case 0x71: // 1Bh 71h XX
8315: case 0x72: // 1Bh 72h XX
1.1.1.37 root 8316: if(pio[c].esc_len == 3) {
8317: pio[c].esc_buf[0] = 0x00;
8318: }
8319: break;
1.1.1.38 root 8320: case 0x24: // 1Bh 24h XX XX
8321: case 0x5c: // 1Bh 5Ch XX XX
1.1.1.37 root 8322: if(pio[c].esc_len == 4) {
8323: pio[c].esc_buf[0] = 0x00;
8324: }
8325: break;
1.1.1.38 root 8326: case 0x2a: // 1Bh 2Ah XX XX XX data
1.1.1.37 root 8327: if(pio[c].esc_len >= 3) {
8328: switch(pio[c].esc_buf[2]) {
8329: case 0: case 1: case 2: case 3: case 4: case 6:
8330: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 1) {
8331: pio[c].esc_buf[0] = 0x00;
8332: }
8333: break;
8334: case 32: case 33: case 38: case 39: case 40:
8335: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 3) {
8336: pio[c].esc_buf[0] = 0x00;
8337: }
8338: break;
1.1.1.38 root 8339: case 71: case 72: case 73:
8340: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 6) {
8341: pio[c].esc_buf[0] = 0x00;
8342: }
8343: break;
1.1.1.37 root 8344: default:
8345: pio[c].esc_buf[0] = 0x00;
8346: break;
8347: }
8348: }
8349: break;
1.1.1.38 root 8350: case 0x40: // 1Bh 40h
1.1.1.37 root 8351: if(pio[c].jis_mode) {
8352: printer_out(c, 0x1c);
8353: printer_out(c, 0x2e);
8354: pio[c].jis_mode = false;
8355: }
8356: pio[c].esc_buf[0] = 0x00;
8357: break;
1.1.1.38 root 8358: case 0x42: // 1Bh 42h data 00h
8359: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8360: if(pio[c].esc_len >= 3 && data == 0) {
8361: pio[c].esc_buf[0] = 0x00;
8362: }
8363: break;
1.1.1.38 root 8364: case 0x43: // 1Bh 43h (00h) XX
1.1.1.37 root 8365: if(pio[c].esc_len >= 3 && data != 0) {
8366: pio[c].esc_buf[0] = 0x00;
8367: }
8368: break;
1.1.1.38 root 8369: default: // 1Bh XX
1.1.1.37 root 8370: pio[c].esc_buf[0] = 0x00;
8371: break;
8372: }
8373: } else if(pio[c].esc_buf[0] == 0x1c) {
8374: printer_out(c, data);
8375: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
8376: pio[c].esc_buf[pio[c].esc_len] = data;
8377: }
8378: pio[c].esc_len++;
8379:
8380: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 8381: case 0x21: // 1Ch 21h XX
8382: case 0x2d: // 1Ch 2Dh XX
8383: case 0x57: // 1Ch 57h XX
8384: case 0x6b: // 1Ch 6Bh XX
8385: case 0x72: // 1Ch 72h XX
8386: case 0x78: // 1Ch 78h XX
1.1.1.37 root 8387: if(pio[c].esc_len == 3) {
8388: pio[c].esc_buf[0] = 0x00;
8389: }
8390: break;
1.1.1.38 root 8391: case 0x26: // 1Ch 26h
1.1.1.37 root 8392: pio[c].jis_mode = true;
8393: pio[c].esc_buf[0] = 0x00;
8394: break;
1.1.1.38 root 8395: case 0x2e: // 1Ch 2Eh
1.1.1.37 root 8396: pio[c].jis_mode = false;
8397: pio[c].esc_buf[0] = 0x00;
8398: break;
1.1.1.38 root 8399: case 0x32: // 1Ch 32h XX XX data
1.1.1.37 root 8400: if(pio[c].esc_len == 76) {
8401: pio[c].esc_buf[0] = 0x00;
8402: }
8403: break;
1.1.1.38 root 8404: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8405: if(pio[c].esc_len == 6) {
8406: pio[c].esc_buf[0] = 0x00;
8407: }
8408: break;
1.1.1.38 root 8409: case 0x53: // 1Ch 53h XX XX
8410: case 0x54: // 1Ch 54h XX XX
1.1.1.37 root 8411: if(pio[c].esc_len == 4) {
8412: pio[c].esc_buf[0] = 0x00;
8413: }
8414: break;
1.1.1.38 root 8415: default: // 1Ch XX
1.1.1.37 root 8416: pio[c].esc_buf[0] = 0x00;
8417: break;
8418: }
8419: } else if(data == 0x1b || data == 0x1c) {
8420: printer_out(c, data);
8421: pio[c].esc_buf[0] = data;
8422: pio[c].esc_len = 1;
8423: } else if((data >= 0x80 && data <= 0x9f) || (data >= 0xe0 && data <= 0xff)) {
8424: pio[c].sjis_hi = data;
8425: } else {
8426: if(pio[c].jis_mode) {
8427: printer_out(c, 0x1c);
8428: printer_out(c, 0x2e);
8429: pio[c].jis_mode = false;
8430: }
8431: printer_out(c, data);
8432: }
8433: } else {
8434: if(pio[c].jis_mode) {
8435: printer_out(c, 0x1c);
8436: printer_out(c, 0x2e);
8437: pio[c].jis_mode = false;
8438: }
8439: printer_out(c, data);
8440: }
8441: }
8442:
8443: inline void pcbios_int_17h_00h()
8444: {
8445: if(REG16(DX) < 3) {
8446: pcbios_printer_out(REG16(DX), REG8(AL));
8447: REG8(AH) = 0xd0;
8448: }
8449: }
8450:
8451: inline void pcbios_int_17h_01h()
8452: {
8453: if(REG16(DX) < 3) {
8454: REG8(AH) = 0xd0;
8455: }
8456: }
8457:
8458: inline void pcbios_int_17h_02h()
8459: {
8460: if(REG16(DX) < 3) {
8461: REG8(AH) = 0xd0;
8462: }
8463: }
8464:
8465: inline void pcbios_int_17h_03h()
8466: {
8467: switch(REG8(AL)) {
8468: case 0x00:
8469: if(REG16(DX) < 3) {
8470: if(pio[REG16(DX)].jis_mode) {
8471: printer_out(REG16(DX), 0x1c);
8472: printer_out(REG16(DX), 0x2e);
8473: pio[REG16(DX)].jis_mode = false;
8474: }
8475: for(UINT16 i = 0; i < REG16(CX); i++) {
8476: printer_out(REG16(DX), mem[SREG_BASE(ES) + REG16(BX) + i]);
8477: }
8478: REG16(CX) = 0x0000;
8479: REG8(AH) = 0xd0;
8480: }
8481: break;
8482: default:
8483: 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));
8484: break;
8485: }
8486: }
8487:
8488: inline void pcbios_int_17h_50h()
8489: {
8490: switch(REG8(AL)) {
8491: case 0x00:
8492: if(REG16(DX) < 3) {
8493: if(REG16(BX) = 0x0001) {
8494: pio[REG16(DX)].conv_mode = false;
8495: REG8(AL) = 0x00;
8496: } else if(REG16(BX) = 0x0051) {
8497: pio[REG16(DX)].conv_mode = true;
8498: REG8(AL) = 0x00;
8499: } else {
8500: REG8(AL) = 0x01;
8501: }
8502: } else {
8503: REG8(AL) = 0x02;
8504: }
8505: break;
8506: case 0x01:
8507: if(REG16(DX) < 3) {
8508: if(pio[REG16(DX)].conv_mode) {
8509: REG16(BX) = 0x0051;
8510: } else {
8511: REG16(BX) = 0x0001;
8512: }
8513: REG8(AL) = 0x00;
8514: } else {
8515: REG8(AL) = 0x02;
8516: }
8517: break;
8518: default:
8519: 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));
8520: break;
8521: }
8522: }
8523:
8524: inline void pcbios_int_17h_51h()
8525: {
8526: if(REG8(DH) >= 0x21 && REG8(DH) <= 0x7e && REG8(DL) >= 0x21 && REG8(DL) <= 0x7e) {
8527: REG16(DX) = pcbios_printer_jis2sjis(REG16(DX));
8528: } else {
8529: REG16(DX) = 0x0000;
8530: }
8531: }
8532:
8533: inline void pcbios_int_17h_52h()
8534: {
8535: if(((REG8(DH) >= 0x81 && REG8(DH) <= 0x9f) || (REG8(DH) >= 0xe0 && REG8(DH) <= 0xfc)) && (REG8(DL) >= 0x40 && REG8(DL) <= 0xfc && REG8(DL) != 0x7f)) {
8536: REG16(DX) = pcbios_printer_sjis2jis(REG16(DX));
8537: } else {
8538: REG16(DX) = 0x0000;
8539: }
8540: }
8541:
8542: inline void pcbios_int_17h_84h()
8543: {
8544: if(REG16(DX) < 3) {
8545: if(pio[REG16(DX)].jis_mode) {
8546: printer_out(REG16(DX), 0x1c);
8547: printer_out(REG16(DX), 0x2e);
8548: pio[REG16(DX)].jis_mode = false;
8549: }
8550: printer_out(REG16(DX), REG8(AL));
8551: REG8(AH) = 0xd0;
8552: }
8553: }
8554:
8555: inline void pcbios_int_17h_85h()
8556: {
8557: pio[0].conv_mode = (REG8(AL) == 0x00);
8558: }
8559:
1.1 root 8560: inline void pcbios_int_1ah_00h()
8561: {
1.1.1.19 root 8562: pcbios_update_daily_timer_counter(timeGetTime());
8563: REG16(CX) = *(UINT16 *)(mem + 0x46e);
8564: REG16(DX) = *(UINT16 *)(mem + 0x46c);
8565: REG8(AL) = mem[0x470];
8566: mem[0x470] = 0;
1.1 root 8567: }
8568:
8569: inline int to_bcd(int t)
8570: {
8571: int u = (t % 100) / 10;
8572: return (u << 4) | (t % 10);
8573: }
8574:
8575: inline void pcbios_int_1ah_02h()
8576: {
8577: SYSTEMTIME time;
8578:
8579: GetLocalTime(&time);
8580: REG8(CH) = to_bcd(time.wHour);
8581: REG8(CL) = to_bcd(time.wMinute);
8582: REG8(DH) = to_bcd(time.wSecond);
8583: REG8(DL) = 0x00;
8584: }
8585:
8586: inline void pcbios_int_1ah_04h()
8587: {
8588: SYSTEMTIME time;
8589:
8590: GetLocalTime(&time);
8591: REG8(CH) = to_bcd(time.wYear / 100);
8592: REG8(CL) = to_bcd(time.wYear);
8593: REG8(DH) = to_bcd(time.wMonth);
8594: REG8(DL) = to_bcd(time.wDay);
8595: }
8596:
8597: inline void pcbios_int_1ah_0ah()
8598: {
8599: SYSTEMTIME time;
8600: FILETIME file_time;
8601: WORD dos_date, dos_time;
8602:
8603: GetLocalTime(&time);
8604: SystemTimeToFileTime(&time, &file_time);
8605: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
8606: REG16(CX) = dos_date;
8607: }
8608:
8609: // msdos system call
8610:
1.1.1.43! root 8611: inline void msdos_int_21h_56h(int lfn);
! 8612:
1.1 root 8613: inline void msdos_int_21h_00h()
8614: {
1.1.1.3 root 8615: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 8616: }
8617:
1.1.1.35 root 8618: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID)
1.1 root 8619: {
8620: REG8(AL) = msdos_getche();
1.1.1.33 root 8621: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8622:
1.1.1.35 root 8623: #ifdef USE_SERVICE_THREAD
8624: service_exit = true;
8625: #endif
8626: return(0);
8627: }
8628:
8629: inline void msdos_int_21h_01h()
8630: {
8631: #ifdef USE_SERVICE_THREAD
8632: start_service_loop(msdos_int_21h_01h_thread);
8633: #else
8634: msdos_int_21h_01h_thread(NULL);
8635: REQUEST_HARDWRE_UPDATE();
8636: #endif
1.1 root 8637: }
8638:
8639: inline void msdos_int_21h_02h()
8640: {
1.1.1.33 root 8641: UINT8 data = REG8(DL);
8642: msdos_putch(data);
8643: REG8(AL) = data;
8644: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8645: }
8646:
8647: inline void msdos_int_21h_03h()
8648: {
8649: REG8(AL) = msdos_aux_in();
8650: }
8651:
8652: inline void msdos_int_21h_04h()
8653: {
8654: msdos_aux_out(REG8(DL));
8655: }
8656:
8657: inline void msdos_int_21h_05h()
8658: {
8659: msdos_prn_out(REG8(DL));
8660: }
8661:
8662: inline void msdos_int_21h_06h()
8663: {
8664: if(REG8(DL) == 0xff) {
8665: if(msdos_kbhit()) {
8666: REG8(AL) = msdos_getch();
1.1.1.3 root 8667: #if defined(HAS_I386)
8668: m_ZF = 0;
8669: #else
8670: m_ZeroVal = 1;
8671: #endif
1.1 root 8672: } else {
8673: REG8(AL) = 0;
1.1.1.3 root 8674: #if defined(HAS_I386)
8675: m_ZF = 1;
8676: #else
8677: m_ZeroVal = 0;
8678: #endif
1.1.1.14 root 8679: maybe_idle();
1.1 root 8680: }
8681: } else {
1.1.1.33 root 8682: UINT8 data = REG8(DL);
8683: msdos_putch(data);
8684: REG8(AL) = data;
1.1 root 8685: }
8686: }
8687:
1.1.1.35 root 8688: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID)
1.1 root 8689: {
8690: REG8(AL) = msdos_getch();
1.1.1.26 root 8691:
1.1.1.35 root 8692: #ifdef USE_SERVICE_THREAD
8693: service_exit = true;
8694: #endif
8695: return(0);
1.1 root 8696: }
8697:
1.1.1.35 root 8698: inline void msdos_int_21h_07h()
8699: {
8700: #ifdef USE_SERVICE_THREAD
8701: start_service_loop(msdos_int_21h_07h_thread);
8702: #else
8703: msdos_int_21h_07h_thread(NULL);
8704: REQUEST_HARDWRE_UPDATE();
8705: #endif
8706: }
8707:
8708: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID)
1.1 root 8709: {
8710: REG8(AL) = msdos_getch();
1.1.1.33 root 8711: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8712:
1.1.1.35 root 8713: #ifdef USE_SERVICE_THREAD
8714: service_exit = true;
8715: #endif
8716: return(0);
8717: }
8718:
8719: inline void msdos_int_21h_08h()
8720: {
8721: #ifdef USE_SERVICE_THREAD
8722: start_service_loop(msdos_int_21h_08h_thread);
8723: #else
8724: msdos_int_21h_08h_thread(NULL);
8725: REQUEST_HARDWRE_UPDATE();
8726: #endif
1.1 root 8727: }
8728:
8729: inline void msdos_int_21h_09h()
8730: {
1.1.1.21 root 8731: msdos_stdio_reopen();
8732:
1.1.1.20 root 8733: process_t *process = msdos_process_info_get(current_psp);
8734: int fd = msdos_psp_get_file_table(1, current_psp);
8735:
1.1.1.14 root 8736: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
8737: int len = 0;
1.1 root 8738:
1.1.1.14 root 8739: while(str[len] != '$' && len < 0x10000) {
8740: len++;
8741: }
1.1.1.20 root 8742: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 8743: // stdout is redirected to file
1.1.1.20 root 8744: msdos_write(fd, str, len);
1.1 root 8745: } else {
8746: for(int i = 0; i < len; i++) {
1.1.1.14 root 8747: msdos_putch(str[i]);
1.1 root 8748: }
8749: }
1.1.1.33 root 8750: REG8(AL) = '$';
8751: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8752: }
8753:
1.1.1.35 root 8754: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID)
1.1 root 8755: {
1.1.1.3 root 8756: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 8757: int max = mem[ofs] - 1;
8758: UINT8 *buf = mem + ofs + 2;
8759: int chr, p = 0;
8760:
8761: while((chr = msdos_getch()) != 0x0d) {
1.1.1.33 root 8762: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 8763: p = 0;
1.1.1.33 root 8764: msdos_putch(0x03);
8765: msdos_putch(0x0d);
8766: msdos_putch(0x0a);
1.1.1.26 root 8767: break;
1.1.1.33 root 8768: } else if(ctrl_break_pressed) {
8769: // skip this byte
1.1.1.26 root 8770: } else if(chr == 0x00) {
1.1 root 8771: // skip 2nd byte
8772: msdos_getch();
8773: } else if(chr == 0x08) {
8774: // back space
8775: if(p > 0) {
8776: p--;
1.1.1.20 root 8777: if(msdos_ctrl_code_check(buf[p])) {
1.1.1.34 root 8778: msdos_putch(0x08);
8779: msdos_putch(0x08);
8780: msdos_putch(0x20);
8781: msdos_putch(0x20);
8782: msdos_putch(0x08);
8783: msdos_putch(0x08);
1.1.1.36 root 8784: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
8785: p--;
8786: msdos_putch(0x08);
8787: msdos_putch(0x08);
8788: msdos_putch(0x20);
8789: msdos_putch(0x20);
8790: msdos_putch(0x08);
8791: msdos_putch(0x08);
1.1.1.34 root 8792: } else {
8793: msdos_putch(0x08);
8794: msdos_putch(0x20);
8795: msdos_putch(0x08);
8796: }
8797: }
8798: } else if(chr == 0x1b) {
8799: // escape
8800: while(p > 0) {
8801: p--;
8802: if(msdos_ctrl_code_check(buf[p])) {
8803: msdos_putch(0x08);
8804: msdos_putch(0x08);
8805: msdos_putch(0x20);
8806: msdos_putch(0x20);
8807: msdos_putch(0x08);
8808: msdos_putch(0x08);
1.1.1.20 root 8809: } else {
1.1.1.34 root 8810: msdos_putch(0x08);
8811: msdos_putch(0x20);
8812: msdos_putch(0x08);
1.1.1.20 root 8813: }
1.1 root 8814: }
8815: } else if(p < max) {
8816: buf[p++] = chr;
8817: msdos_putch(chr);
8818: }
8819: }
8820: buf[p] = 0x0d;
8821: mem[ofs + 1] = p;
1.1.1.33 root 8822: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8823:
1.1.1.35 root 8824: #ifdef USE_SERVICE_THREAD
8825: service_exit = true;
8826: #endif
8827: return(0);
8828: }
8829:
8830: inline void msdos_int_21h_0ah()
8831: {
8832: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) {
8833: #ifdef USE_SERVICE_THREAD
8834: start_service_loop(msdos_int_21h_0ah_thread);
8835: #else
8836: msdos_int_21h_0ah_thread(NULL);
8837: REQUEST_HARDWRE_UPDATE();
8838: #endif
8839: }
1.1 root 8840: }
8841:
8842: inline void msdos_int_21h_0bh()
8843: {
8844: if(msdos_kbhit()) {
8845: REG8(AL) = 0xff;
8846: } else {
8847: REG8(AL) = 0x00;
1.1.1.14 root 8848: maybe_idle();
1.1 root 8849: }
1.1.1.33 root 8850: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8851: }
8852:
8853: inline void msdos_int_21h_0ch()
8854: {
8855: // clear key buffer
1.1.1.21 root 8856: msdos_stdio_reopen();
8857:
1.1.1.20 root 8858: process_t *process = msdos_process_info_get(current_psp);
8859: int fd = msdos_psp_get_file_table(0, current_psp);
8860:
8861: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 8862: // stdin is redirected to file
8863: } else {
8864: while(msdos_kbhit()) {
8865: msdos_getch();
8866: }
8867: }
8868:
8869: switch(REG8(AL)) {
8870: case 0x01:
8871: msdos_int_21h_01h();
8872: break;
8873: case 0x06:
8874: msdos_int_21h_06h();
8875: break;
8876: case 0x07:
8877: msdos_int_21h_07h();
8878: break;
8879: case 0x08:
8880: msdos_int_21h_08h();
8881: break;
8882: case 0x0a:
8883: msdos_int_21h_0ah();
8884: break;
8885: default:
1.1.1.22 root 8886: // 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));
8887: // REG16(AX) = 0x01;
8888: // m_CF = 1;
1.1 root 8889: break;
8890: }
8891: }
8892:
8893: inline void msdos_int_21h_0dh()
8894: {
8895: }
8896:
8897: inline void msdos_int_21h_0eh()
8898: {
8899: if(REG8(DL) < 26) {
8900: _chdrive(REG8(DL) + 1);
8901: msdos_cds_update(REG8(DL));
1.1.1.23 root 8902: msdos_sda_update(current_psp);
1.1 root 8903: }
8904: REG8(AL) = 26; // zdrive
8905: }
8906:
1.1.1.14 root 8907: inline void msdos_int_21h_0fh()
8908: {
8909: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8910: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8911: char *path = msdos_fcb_path(fcb);
8912: 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 8913:
1.1.1.14 root 8914: if(hFile == INVALID_HANDLE_VALUE) {
8915: REG8(AL) = 0xff;
8916: } else {
8917: REG8(AL) = 0;
8918: fcb->current_block = 0;
8919: fcb->record_size = 128;
8920: fcb->file_size = GetFileSize(hFile, NULL);
8921: fcb->handle = hFile;
8922: fcb->cur_record = 0;
8923: }
8924: }
8925:
8926: inline void msdos_int_21h_10h()
8927: {
8928: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8929: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8930:
8931: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
8932: }
8933:
1.1 root 8934: inline void msdos_int_21h_11h()
8935: {
1.1.1.3 root 8936: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8937: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8938:
8939: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 8940: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8941: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
8942: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8943: char *path = msdos_fcb_path(fcb);
8944: WIN32_FIND_DATA fd;
8945:
1.1.1.13 root 8946: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
8947: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8948: FindClose(dtainfo->find_handle);
8949: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8950: }
8951: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 8952: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
8953: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 8954:
1.1.1.14 root 8955: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
8956: dtainfo->allowable_mask &= ~8;
1.1 root 8957: }
1.1.1.14 root 8958: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
8959: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 8960: !msdos_find_file_has_8dot3name(&fd)) {
8961: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8962: FindClose(dtainfo->find_handle);
8963: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8964: break;
8965: }
8966: }
8967: }
1.1.1.13 root 8968: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8969: if(ext_fcb->flag == 0xff) {
8970: ext_find->flag = 0xff;
8971: memset(ext_find->reserved, 0, 5);
8972: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8973: }
8974: find->drive = _getdrive();
1.1.1.13 root 8975: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 8976: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8977: find->nt_res = 0;
8978: msdos_find_file_conv_local_time(&fd);
8979: find->create_time_ms = 0;
8980: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8981: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8982: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8983: find->cluster_hi = find->cluster_lo = 0;
8984: find->file_size = fd.nFileSizeLow;
8985: REG8(AL) = 0x00;
1.1.1.14 root 8986: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8987: if(ext_fcb->flag == 0xff) {
8988: ext_find->flag = 0xff;
8989: memset(ext_find->reserved, 0, 5);
8990: ext_find->attribute = 8;
8991: }
8992: find->drive = _getdrive();
8993: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
8994: find->attribute = 8;
8995: find->nt_res = 0;
8996: msdos_find_file_conv_local_time(&fd);
8997: find->create_time_ms = 0;
8998: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8999: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9000: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9001: find->cluster_hi = find->cluster_lo = 0;
9002: find->file_size = 0;
1.1.1.14 root 9003: dtainfo->allowable_mask &= ~8;
1.1 root 9004: REG8(AL) = 0x00;
9005: } else {
9006: REG8(AL) = 0xff;
9007: }
9008: }
9009:
9010: inline void msdos_int_21h_12h()
9011: {
1.1.1.3 root 9012: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 9013: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9014:
9015: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9016: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9017: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
9018: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 9019: WIN32_FIND_DATA fd;
9020:
1.1.1.13 root 9021: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
9022: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9023: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 9024: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9025: !msdos_find_file_has_8dot3name(&fd)) {
9026: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9027: FindClose(dtainfo->find_handle);
9028: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9029: break;
9030: }
9031: }
9032: } else {
1.1.1.13 root 9033: FindClose(dtainfo->find_handle);
9034: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9035: }
9036: }
1.1.1.13 root 9037: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9038: if(ext_fcb->flag == 0xff) {
9039: ext_find->flag = 0xff;
9040: memset(ext_find->reserved, 0, 5);
9041: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9042: }
9043: find->drive = _getdrive();
1.1.1.13 root 9044: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 9045: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
9046: find->nt_res = 0;
9047: msdos_find_file_conv_local_time(&fd);
9048: find->create_time_ms = 0;
9049: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9050: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9051: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9052: find->cluster_hi = find->cluster_lo = 0;
9053: find->file_size = fd.nFileSizeLow;
9054: REG8(AL) = 0x00;
1.1.1.14 root 9055: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9056: if(ext_fcb->flag == 0xff) {
9057: ext_find->flag = 0xff;
9058: memset(ext_find->reserved, 0, 5);
9059: ext_find->attribute = 8;
9060: }
9061: find->drive = _getdrive();
9062: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
9063: find->attribute = 8;
9064: find->nt_res = 0;
9065: msdos_find_file_conv_local_time(&fd);
9066: find->create_time_ms = 0;
9067: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
9068: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
9069: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
9070: find->cluster_hi = find->cluster_lo = 0;
9071: find->file_size = 0;
1.1.1.14 root 9072: dtainfo->allowable_mask &= ~8;
1.1 root 9073: REG8(AL) = 0x00;
9074: } else {
9075: REG8(AL) = 0xff;
9076: }
9077: }
9078:
9079: inline void msdos_int_21h_13h()
9080: {
1.1.1.3 root 9081: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 9082: REG8(AL) = 0xff;
9083: } else {
9084: REG8(AL) = 0x00;
9085: }
9086: }
9087:
1.1.1.16 root 9088: inline void msdos_int_21h_14h()
9089: {
9090: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9091: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9092: process_t *process = msdos_process_info_get(current_psp);
9093: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9094: DWORD num = 0;
9095:
9096: memset(mem + dta_laddr, 0, fcb->record_size);
9097: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9098: REG8(AL) = 1;
9099: } else {
9100: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
9101: fcb->current_block = (position & 0xffffff) / fcb->record_size;
9102: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
9103: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
9104: }
9105: }
9106:
9107: inline void msdos_int_21h_15h()
1.1.1.14 root 9108: {
9109: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9110: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 9111: process_t *process = msdos_process_info_get(current_psp);
9112: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9113: DWORD num = 0;
1.1.1.14 root 9114:
1.1.1.16 root 9115: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9116: REG8(AL) = 1;
9117: } else {
9118: fcb->file_size = GetFileSize(fcb->handle, NULL);
9119: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
9120: fcb->current_block = (position & 0xffffff) / fcb->record_size;
9121: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
9122: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
9123: }
9124: }
9125:
9126: inline void msdos_int_21h_16h()
9127: {
9128: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9129: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 9130: char *path = msdos_fcb_path(fcb);
9131: 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 9132:
1.1.1.14 root 9133: if(hFile == INVALID_HANDLE_VALUE) {
9134: REG8(AL) = 0xff;
9135: } else {
9136: REG8(AL) = 0;
9137: fcb->current_block = 0;
9138: fcb->record_size = 128;
9139: fcb->file_size = 0;
9140: fcb->handle = hFile;
9141: fcb->cur_record = 0;
9142: }
9143: }
9144:
1.1.1.16 root 9145: inline void msdos_int_21h_17h()
9146: {
9147: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9148: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
9149: char *path_src = msdos_fcb_path(fcb_src);
9150: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
9151: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
9152: char *path_dst = msdos_fcb_path(fcb_dst);
9153:
9154: if(rename(path_src, path_dst)) {
9155: REG8(AL) = 0xff;
9156: } else {
9157: REG8(AL) = 0;
9158: }
9159: }
9160:
1.1 root 9161: inline void msdos_int_21h_18h()
9162: {
9163: REG8(AL) = 0x00;
9164: }
9165:
9166: inline void msdos_int_21h_19h()
9167: {
9168: REG8(AL) = _getdrive() - 1;
9169: }
9170:
9171: inline void msdos_int_21h_1ah()
9172: {
9173: process_t *process = msdos_process_info_get(current_psp);
9174:
9175: process->dta.w.l = REG16(DX);
1.1.1.3 root 9176: process->dta.w.h = SREG(DS);
1.1.1.23 root 9177: msdos_sda_update(current_psp);
1.1 root 9178: }
9179:
9180: inline void msdos_int_21h_1bh()
9181: {
9182: int drive_num = _getdrive() - 1;
9183: UINT16 seg, ofs;
9184:
9185: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9186: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9187: REG8(AL) = dpb->highest_sector_num + 1;
9188: REG16(CX) = dpb->bytes_per_sector;
9189: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 9190: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 9191: } else {
9192: REG8(AL) = 0xff;
1.1.1.3 root 9193: m_CF = 1;
1.1 root 9194: }
9195:
9196: }
9197:
9198: inline void msdos_int_21h_1ch()
9199: {
1.1.1.41 root 9200: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
1.1 root 9201: UINT16 seg, ofs;
9202:
9203: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9204: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
9205: REG8(AL) = dpb->highest_sector_num + 1;
9206: REG16(CX) = dpb->bytes_per_sector;
9207: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 9208: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 9209: } else {
9210: REG8(AL) = 0xff;
1.1.1.3 root 9211: m_CF = 1;
1.1 root 9212: }
9213:
9214: }
9215:
9216: inline void msdos_int_21h_1dh()
9217: {
9218: REG8(AL) = 0;
9219: }
9220:
9221: inline void msdos_int_21h_1eh()
9222: {
9223: REG8(AL) = 0;
9224: }
9225:
9226: inline void msdos_int_21h_1fh()
9227: {
9228: int drive_num = _getdrive() - 1;
9229: UINT16 seg, ofs;
9230:
9231: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9232: REG8(AL) = 0;
1.1.1.3 root 9233: SREG(DS) = seg;
9234: i386_load_segment_descriptor(DS);
1.1 root 9235: REG16(BX) = ofs;
9236: } else {
9237: REG8(AL) = 0xff;
1.1.1.3 root 9238: m_CF = 1;
1.1 root 9239: }
9240: }
9241:
9242: inline void msdos_int_21h_20h()
9243: {
9244: REG8(AL) = 0;
9245: }
9246:
1.1.1.14 root 9247: inline void msdos_int_21h_21h()
9248: {
9249: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9250: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9251:
9252: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9253: REG8(AL) = 1;
9254: } else {
9255: process_t *process = msdos_process_info_get(current_psp);
9256: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9257: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 9258: DWORD num = 0;
1.1.1.14 root 9259: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
9260: REG8(AL) = 1;
9261: } else {
9262: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9263: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 9264: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 9265: }
9266: }
9267: }
9268:
9269: inline void msdos_int_21h_22h()
9270: {
9271: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9272: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9273:
9274: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9275: REG8(AL) = 0xff;
9276: } else {
9277: process_t *process = msdos_process_info_get(current_psp);
9278: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 9279: DWORD num = 0;
1.1.1.14 root 9280: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
9281: fcb->file_size = GetFileSize(fcb->handle, NULL);
9282: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9283: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 9284: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 9285: }
9286: }
9287:
1.1.1.16 root 9288: inline void msdos_int_21h_23h()
9289: {
9290: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9291: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9292: char *path = msdos_fcb_path(fcb);
9293: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9294:
9295: if(hFile == INVALID_HANDLE_VALUE) {
9296: REG8(AL) = 0xff;
9297: } else {
9298: UINT32 size = GetFileSize(hFile, NULL);
9299: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
9300: REG8(AL) = 0;
9301: }
9302: }
9303:
9304: inline void msdos_int_21h_24h()
9305: {
9306: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9307: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9308:
9309: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
9310: }
9311:
1.1 root 9312: inline void msdos_int_21h_25h()
9313: {
9314: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 9315: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 9316: }
9317:
9318: inline void msdos_int_21h_26h()
9319: {
9320: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
9321:
9322: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
9323: psp->first_mcb = REG16(DX) + 16;
9324: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
9325: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
9326: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
9327: psp->parent_psp = 0;
9328: }
9329:
1.1.1.16 root 9330: inline void msdos_int_21h_27h()
9331: {
9332: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9333: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9334:
9335: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9336: REG8(AL) = 1;
9337: } else {
9338: process_t *process = msdos_process_info_get(current_psp);
9339: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9340: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
9341: DWORD num = 0;
9342: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
9343: REG8(AL) = 1;
9344: } else {
9345: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9346: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9347: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
9348: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9349: }
9350: }
9351: }
9352:
9353: inline void msdos_int_21h_28h()
9354: {
9355: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9356: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9357:
9358: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9359: REG8(AL) = 0xff;
9360: } else {
9361: process_t *process = msdos_process_info_get(current_psp);
9362: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9363: DWORD num = 0;
9364: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
9365: fcb->file_size = GetFileSize(fcb->handle, NULL);
9366: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9367: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9368: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
9369: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9370: }
9371: }
9372:
1.1 root 9373: inline void msdos_int_21h_29h()
9374: {
1.1.1.20 root 9375: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
9376: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 9377: UINT8 drv = 0;
9378: char sep_chars[] = ":.;,=+";
9379: char end_chars[] = "\\<>|/\"[]";
9380: char spc_chars[] = " \t";
9381:
1.1.1.20 root 9382: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
9383: buffer[1023] = 0;
9384: memset(name, 0x20, sizeof(name));
9385: memset(ext, 0x20, sizeof(ext));
9386:
1.1 root 9387: if(REG8(AL) & 1) {
1.1.1.20 root 9388: ofs += strspn((char *)(buffer + ofs), spc_chars);
9389: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 9390: ofs++;
9391: }
9392: }
1.1.1.20 root 9393: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 9394:
1.1.1.24 root 9395: if(buffer[ofs + 1] == ':') {
9396: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
9397: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 9398: ofs += 2;
1.1.1.24 root 9399: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9400: ofs++;
9401: }
9402: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
9403: drv = buffer[ofs] - 'A' + 1;
1.1 root 9404: ofs += 2;
1.1.1.24 root 9405: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9406: ofs++;
9407: }
1.1 root 9408: }
9409: }
1.1.1.20 root 9410: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9411: UINT8 c = buffer[ofs];
9412: if(is_kanji) {
9413: is_kanji = 0;
9414: } else if(msdos_lead_byte_check(c)) {
9415: is_kanji = 1;
9416: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9417: break;
9418: } else if(c >= 'a' && c <= 'z') {
9419: c -= 0x20;
9420: }
9421: ofs++;
9422: name[i] = c;
9423: }
1.1.1.20 root 9424: if(buffer[ofs] == '.') {
1.1 root 9425: ofs++;
1.1.1.20 root 9426: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9427: UINT8 c = buffer[ofs];
9428: if(is_kanji) {
9429: is_kanji = 0;
9430: } else if(msdos_lead_byte_check(c)) {
9431: is_kanji = 1;
9432: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9433: break;
9434: } else if(c >= 'a' && c <= 'z') {
9435: c -= 0x20;
9436: }
9437: ofs++;
9438: ext[i] = c;
9439: }
9440: }
1.1.1.20 root 9441: int si = REG16(SI) + ofs;
1.1.1.3 root 9442: int ds = SREG(DS);
1.1 root 9443: while(si > 0xffff) {
9444: si -= 0x10;
9445: ds++;
9446: }
9447: REG16(SI) = si;
1.1.1.3 root 9448: SREG(DS) = ds;
9449: i386_load_segment_descriptor(DS);
1.1 root 9450:
1.1.1.3 root 9451: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 9452: if(!(REG8(AL) & 2) || drv != 0) {
9453: fcb[0] = drv;
9454: }
9455: if(!(REG8(AL) & 4) || name[0] != 0x20) {
9456: memcpy(fcb + 1, name, 8);
9457: }
9458: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
9459: memcpy(fcb + 9, ext, 3);
9460: }
9461: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 9462: if(fcb[i] == '*') {
9463: found_star = 1;
9464: }
9465: if(found_star) {
9466: fcb[i] = '?';
9467: }
9468: }
1.1.1.20 root 9469: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 9470: if(fcb[i] == '*') {
9471: found_star = 1;
9472: }
9473: if(found_star) {
9474: fcb[i] = '?';
9475: }
9476: }
9477:
9478: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
9479: if(memchr(fcb + 1, '?', 8 + 3)) {
9480: REG8(AL) = 0x01;
1.1.1.20 root 9481: } else {
9482: REG8(AL) = 0x00;
1.1 root 9483: }
9484: } else {
9485: REG8(AL) = 0xff;
9486: }
9487: }
9488:
9489: inline void msdos_int_21h_2ah()
9490: {
9491: SYSTEMTIME sTime;
9492:
9493: GetLocalTime(&sTime);
9494: REG16(CX) = sTime.wYear;
9495: REG8(DH) = (UINT8)sTime.wMonth;
9496: REG8(DL) = (UINT8)sTime.wDay;
9497: REG8(AL) = (UINT8)sTime.wDayOfWeek;
9498: }
9499:
9500: inline void msdos_int_21h_2bh()
9501: {
1.1.1.14 root 9502: REG8(AL) = 0xff;
1.1 root 9503: }
9504:
9505: inline void msdos_int_21h_2ch()
9506: {
9507: SYSTEMTIME sTime;
9508:
9509: GetLocalTime(&sTime);
9510: REG8(CH) = (UINT8)sTime.wHour;
9511: REG8(CL) = (UINT8)sTime.wMinute;
9512: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 9513: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 9514: }
9515:
9516: inline void msdos_int_21h_2dh()
9517: {
9518: REG8(AL) = 0x00;
9519: }
9520:
9521: inline void msdos_int_21h_2eh()
9522: {
9523: process_t *process = msdos_process_info_get(current_psp);
9524:
9525: process->verify = REG8(AL);
9526: }
9527:
9528: inline void msdos_int_21h_2fh()
9529: {
9530: process_t *process = msdos_process_info_get(current_psp);
9531:
9532: REG16(BX) = process->dta.w.l;
1.1.1.3 root 9533: SREG(ES) = process->dta.w.h;
9534: i386_load_segment_descriptor(ES);
1.1 root 9535: }
9536:
9537: inline void msdos_int_21h_30h()
9538: {
9539: // Version Flag / OEM
1.1.1.27 root 9540: if(REG8(AL) == 0x01) {
1.1.1.29 root 9541: #ifdef SUPPORT_HMA
9542: REG16(BX) = 0x0000;
9543: #else
9544: REG16(BX) = 0x1000; // DOS is in HMA
9545: #endif
1.1 root 9546: } else {
1.1.1.27 root 9547: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
9548: // but this is not correct on Windows 98 SE
9549: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
9550: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 9551: }
1.1.1.27 root 9552: REG16(CX) = 0x0000;
1.1.1.30 root 9553: REG8(AL) = dos_major_version; // 7
9554: REG8(AH) = dos_minor_version; // 10
1.1 root 9555: }
9556:
9557: inline void msdos_int_21h_31h()
9558: {
1.1.1.29 root 9559: try {
9560: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9561: } catch(...) {
9562: // recover the broken mcb
9563: int mcb_seg = current_psp - 1;
9564: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 9565:
1.1.1.29 root 9566: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 9567: mcb->mz = 'M';
9568: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
9569:
1.1.1.29 root 9570: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 9571: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 9572: } else {
1.1.1.39 root 9573: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 9574: }
9575: } else {
9576: mcb->mz = 'Z';
1.1.1.30 root 9577: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 9578: }
9579: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9580: }
1.1 root 9581: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
9582: }
9583:
9584: inline void msdos_int_21h_32h()
9585: {
9586: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
9587: UINT16 seg, ofs;
9588:
9589: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9590: REG8(AL) = 0;
1.1.1.3 root 9591: SREG(DS) = seg;
9592: i386_load_segment_descriptor(DS);
1.1 root 9593: REG16(BX) = ofs;
9594: } else {
9595: REG8(AL) = 0xff;
1.1.1.3 root 9596: m_CF = 1;
1.1 root 9597: }
9598: }
9599:
9600: inline void msdos_int_21h_33h()
9601: {
9602: char path[MAX_PATH];
9603:
9604: switch(REG8(AL)) {
9605: case 0x00:
1.1.1.33 root 9606: REG8(DL) = ctrl_break_checking;
1.1 root 9607: break;
9608: case 0x01:
1.1.1.33 root 9609: ctrl_break_checking = REG8(DL);
9610: break;
9611: case 0x02:
9612: {
9613: UINT8 old = ctrl_break_checking;
9614: ctrl_break_checking = REG8(DL);
9615: REG8(DL) = old;
9616: }
9617: break;
9618: case 0x03:
9619: case 0x04:
9620: // DOS 4.0+ - Unused
1.1 root 9621: break;
9622: case 0x05:
9623: GetSystemDirectory(path, MAX_PATH);
9624: if(path[0] >= 'a' && path[0] <= 'z') {
9625: REG8(DL) = path[0] - 'a' + 1;
9626: } else {
9627: REG8(DL) = path[0] - 'A' + 1;
9628: }
9629: break;
9630: case 0x06:
1.1.1.2 root 9631: // MS-DOS version (7.10)
1.1 root 9632: REG8(BL) = 7;
1.1.1.2 root 9633: REG8(BH) = 10;
1.1 root 9634: REG8(DL) = 0;
1.1.1.29 root 9635: #ifdef SUPPORT_HMA
9636: REG8(DH) = 0x00;
9637: #else
9638: REG8(DH) = 0x10; // DOS is in HMA
9639: #endif
1.1 root 9640: break;
1.1.1.6 root 9641: case 0x07:
9642: if(REG8(DL) == 0) {
9643: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
9644: } else if(REG8(DL) == 1) {
9645: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
9646: }
9647: break;
1.1 root 9648: default:
1.1.1.22 root 9649: 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 9650: REG16(AX) = 0x01;
1.1.1.3 root 9651: m_CF = 1;
1.1 root 9652: break;
9653: }
9654: }
9655:
1.1.1.23 root 9656: inline void msdos_int_21h_34h()
9657: {
9658: SREG(ES) = SDA_TOP >> 4;
9659: i386_load_segment_descriptor(ES);
9660: REG16(BX) = offsetof(sda_t, indos_flag);;
9661: }
9662:
1.1 root 9663: inline void msdos_int_21h_35h()
9664: {
9665: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 9666: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
9667: i386_load_segment_descriptor(ES);
1.1 root 9668: }
9669:
9670: inline void msdos_int_21h_36h()
9671: {
9672: struct _diskfree_t df = {0};
9673:
9674: if(_getdiskfree(REG8(DL), &df) == 0) {
9675: REG16(AX) = (UINT16)df.sectors_per_cluster;
9676: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 9677: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
9678: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 9679: } else {
9680: REG16(AX) = 0xffff;
9681: }
9682: }
9683:
9684: inline void msdos_int_21h_37h()
9685: {
1.1.1.22 root 9686: static UINT8 dev_flag = 0xff;
1.1 root 9687:
9688: switch(REG8(AL)) {
9689: case 0x00:
1.1.1.22 root 9690: {
9691: process_t *process = msdos_process_info_get(current_psp);
9692: REG8(AL) = 0x00;
9693: REG8(DL) = process->switchar;
9694: }
1.1 root 9695: break;
9696: case 0x01:
1.1.1.22 root 9697: {
9698: process_t *process = msdos_process_info_get(current_psp);
9699: REG8(AL) = 0x00;
9700: process->switchar = REG8(DL);
1.1.1.23 root 9701: msdos_sda_update(current_psp);
1.1.1.22 root 9702: }
9703: break;
9704: case 0x02:
9705: REG8(DL) = dev_flag;
9706: break;
9707: case 0x03:
9708: dev_flag = REG8(DL);
9709: break;
9710: case 0xd0:
9711: case 0xd1:
9712: case 0xd2:
9713: case 0xd3:
9714: case 0xd4:
9715: case 0xd5:
9716: case 0xd6:
9717: case 0xd7:
9718: case 0xdc:
9719: case 0xdd:
9720: case 0xde:
9721: case 0xdf:
9722: // diet ???
9723: REG16(AX) = 1;
1.1 root 9724: break;
9725: default:
1.1.1.22 root 9726: 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 9727: REG16(AX) = 1;
9728: break;
9729: }
9730: }
9731:
1.1.1.42 root 9732: int get_country_info(country_info_t *ci, LCID locale)
1.1.1.17 root 9733: {
9734: char LCdata[80];
9735:
1.1.1.19 root 9736: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.42 root 9737: GetLocaleInfo(locale, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
1.1.1.17 root 9738: ci->currency_dec_digits = atoi(LCdata);
1.1.1.42 root 9739: GetLocaleInfo(locale, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
1.1.1.17 root 9740: ci->currency_format = *LCdata - '0';
1.1.1.42 root 9741: GetLocaleInfo(locale, LOCALE_IDATE, LCdata, sizeof(LCdata));
1.1.1.17 root 9742: ci->date_format = *LCdata - '0';
1.1.1.42 root 9743: GetLocaleInfo(locale, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
1.1.1.17 root 9744: memcpy(&ci->currency_symbol, LCdata, 4);
1.1.1.42 root 9745: GetLocaleInfo(locale, LOCALE_SDATE, LCdata, sizeof(LCdata));
1.1.1.17 root 9746: *ci->date_sep = *LCdata;
1.1.1.42 root 9747: GetLocaleInfo(locale, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
1.1.1.17 root 9748: *ci->dec_sep = *LCdata;
1.1.1.42 root 9749: GetLocaleInfo(locale, LOCALE_SLIST, LCdata, sizeof(LCdata));
1.1.1.17 root 9750: *ci->list_sep = *LCdata;
1.1.1.42 root 9751: GetLocaleInfo(locale, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
1.1.1.17 root 9752: *ci->thou_sep = *LCdata;
1.1.1.42 root 9753: GetLocaleInfo(locale, LOCALE_STIME, LCdata, sizeof(LCdata));
1.1.1.17 root 9754: *ci->time_sep = *LCdata;
1.1.1.42 root 9755: GetLocaleInfo(locale, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
1.1.1.17 root 9756: if(strchr(LCdata, 'H') != NULL) {
9757: ci->time_format = 1;
9758: }
1.1.1.27 root 9759: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 9760: ci->case_map.w.h = 0xfffd;
1.1.1.42 root 9761: GetLocaleInfo(locale, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
1.1.1.17 root 9762: return atoi(LCdata);
9763: }
9764:
1.1.1.42 root 9765: int get_country_info(country_info_t *ci, USHORT usPrimaryLanguage, USHORT usSubLanguage)
9766: {
9767: return get_country_info(ci, MAKELCID(MAKELANGID(usPrimaryLanguage, usSubLanguage), SORT_DEFAULT));
9768: }
9769:
9770: int get_country_info(country_info_t *ci)
9771: {
9772: return get_country_info(ci, LOCALE_USER_DEFAULT);
9773: }
9774:
1.1.1.43! root 9775: void set_country_info(country_info_t *ci, int size)
! 9776: {
! 9777: char LCdata[80];
! 9778:
! 9779: if(size >= 0x00 + 2) {
! 9780: memset(LCdata, 0, sizeof(LCdata));
! 9781: *LCdata = '0' + ci->date_format;
! 9782: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata);
! 9783: }
! 9784: if(size >= 0x02 + 5) {
! 9785: memset(LCdata, 0, sizeof(LCdata));
! 9786: memcpy(LCdata, &ci->currency_symbol, 4);
! 9787: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata);
! 9788: }
! 9789: if(size >= 0x07 + 2) {
! 9790: memset(LCdata, 0, sizeof(LCdata));
! 9791: *LCdata = *ci->thou_sep;
! 9792: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata);
! 9793: }
! 9794: if(size >= 0x09 + 2) {
! 9795: memset(LCdata, 0, sizeof(LCdata));
! 9796: *LCdata = *ci->dec_sep;
! 9797: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata);
! 9798: }
! 9799: if(size >= 0x0b + 2) {
! 9800: memset(LCdata, 0, sizeof(LCdata));
! 9801: *LCdata = *ci->date_sep;
! 9802: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata);
! 9803: }
! 9804: if(size >= 0x0d + 2) {
! 9805: memset(LCdata, 0, sizeof(LCdata));
! 9806: *LCdata = *ci->time_sep;
! 9807: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata);
! 9808: }
! 9809: if(size >= 0x0f + 1) {
! 9810: memset(LCdata, 0, sizeof(LCdata));
! 9811: *LCdata = '0' + ci->currency_format;
! 9812: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata);
! 9813: }
! 9814: if(size >= 0x10 + 1) {
! 9815: sprintf(LCdata, "%d", ci->currency_dec_digits);
! 9816: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata);
! 9817: }
! 9818: if(size >= 0x11 + 1) {
! 9819: // FIXME: is time format always H/h:mm:ss ???
! 9820: if(ci->time_format & 1) {
! 9821: sprintf(LCdata, "H%cmm%css", *ci->time_sep, *ci->time_sep);
! 9822: } else {
! 9823: sprintf(LCdata, "h%cmm%css", *ci->time_sep, *ci->time_sep);
! 9824: }
! 9825: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata);
! 9826: }
! 9827: if(size >= 0x12 + 4) {
! 9828: // 12h DWORD address of case map routine
! 9829: // (FAR CALL, AL = character to map to upper case [>= 80h])
! 9830: }
! 9831: if(size >= 0x16 + 2) {
! 9832: memset(LCdata, 0, sizeof(LCdata));
! 9833: *LCdata = *ci->list_sep;
! 9834: SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata);
! 9835: }
! 9836: }
! 9837:
1.1.1.42 root 9838: #ifndef SUBLANG_SWAHILI
9839: #define SUBLANG_SWAHILI 0x01
9840: #endif
9841: #ifndef SUBLANG_TSWANA_BOTSWANA
9842: #define SUBLANG_TSWANA_BOTSWANA 0x02
9843: #endif
9844: #ifndef SUBLANG_LITHUANIAN_LITHUANIA
9845: #define SUBLANG_LITHUANIAN_LITHUANIA 0x01
9846: #endif
9847: #ifndef LANG_BANGLA
9848: #define LANG_BANGLA 0x45
9849: #endif
9850: #ifndef SUBLANG_BANGLA_BANGLADESH
9851: #define SUBLANG_BANGLA_BANGLADESH 0x02
9852: #endif
9853:
9854: static const struct {
9855: int code;
9856: USHORT usPrimaryLanguage;
9857: USHORT usSubLanguage;
9858: } country_table[] = {
9859: {0x001, LANG_ENGLISH, SUBLANG_ENGLISH_US}, // United States
9860: {0x002, LANG_FRENCH, SUBLANG_FRENCH_CANADIAN}, // Canadian-French
9861: {0x004, LANG_ENGLISH, SUBLANG_ENGLISH_CAN}, // Canada (English)
9862: {0x007, LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA}, // Russia
9863: {0x014, LANG_ARABIC, SUBLANG_ARABIC_EGYPT}, // Egypt
9864: {0x01B, LANG_ZULU, SUBLANG_ZULU_SOUTH_AFRICA}, // South Africa
9865: // {0x01B, LANG_XHOSA, SUBLANG_XHOSA_SOUTH_AFRICA}, // South Africa
9866: // {0x01B, LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA}, // South Africa
9867: // {0x01B, LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA}, // South Africa
9868: // {0x01B, LANG_SOTHO, SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA}, // South Africa
9869: // {0x01B, LANG_TSWANA, SUBLANG_TSWANA_SOUTH_AFRICA}, // South Africa
9870: {0x01E, LANG_GREEK, SUBLANG_GREEK_GREECE}, // Greece
9871: {0x01F, LANG_DUTCH, SUBLANG_DUTCH}, // Netherlands
9872: // {0x01F, LANG_FRISIAN, SUBLANG_FRISIAN_NETHERLANDS}, // Netherlands
9873: {0x020, LANG_DUTCH, SUBLANG_DUTCH_BELGIAN}, // Belgium
9874: // {0x020, LANG_FRENCH, SUBLANG_FRENCH_BELGIAN}, // Belgium
9875: {0x021, LANG_FRENCH, SUBLANG_FRENCH}, // France
9876: {0x022, LANG_SPANISH, SUBLANG_SPANISH}, // Spain
9877: {0x023, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria???
9878: {0x024, LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY}, // Hungary (not supported by DR DOS 5.0)
9879: {0x027, LANG_ITALIAN, SUBLANG_ITALIAN}, // Italy / San Marino / Vatican City
9880: {0x028, LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA}, // Romania
9881: {0x029, LANG_GERMAN, SUBLANG_GERMAN_SWISS}, // Switzerland / Liechtenstein
9882: // {0x029, LANG_FRENCH, SUBLANG_FRENCH_SWISS}, // Switzerland / Liechtenstein
9883: // {0x029, LANG_ITALIAN, SUBLANG_ITALIAN_SWISS}, // Switzerland / Liechtenstein
9884: {0x02A, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0)
9885: {0x02B, LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN}, // Austria (DR DOS 5.0)
9886: {0x02C, LANG_ENGLISH, SUBLANG_ENGLISH_UK}, // United Kingdom
9887: {0x02D, LANG_DANISH, SUBLANG_DANISH_DENMARK}, // Denmark
9888: {0x02E, LANG_SWEDISH, SUBLANG_SWEDISH}, // Sweden
9889: // {0x02E, LANG_SAMI, SUBLANG_SAMI_NORTHERN_SWEDEN}, // Sweden
9890: // {0x02E, LANG_SAMI, SUBLANG_SAMI_LULE_SWEDEN}, // Sweden
9891: // {0x02E, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_SWEDEN}, // Sweden
9892: {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL}, // Norway
9893: // {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK}, // Norway
9894: // {0x02F, LANG_SAMI, SUBLANG_SAMI_NORTHERN_NORWAY}, // Norway
9895: // {0x02F, LANG_SAMI, SUBLANG_SAMI_LULE_NORWAY}, // Norway
9896: // {0x02F, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_NORWAY}, // Norway
9897: {0x030, LANG_POLISH, SUBLANG_POLISH_POLAND}, // Poland (not supported by DR DOS 5.0)
9898: {0x031, LANG_GERMAN, SUBLANG_GERMAN}, // Germany
9899: {0x033, LANG_SPANISH, SUBLANG_SPANISH_PERU}, // Peru
9900: // {0x033, LANG_QUECHUA, SUBLANG_QUECHUA_PERU}, // Peru
9901: {0x034, LANG_SPANISH, SUBLANG_SPANISH_MEXICAN}, // Mexico
9902: {0x035, LANG_SPANISH, SUBLANG_NEUTRAL}, // Cuba
9903: {0x036, LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA}, // Argentina
9904: {0x037, LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN}, // Brazil (not supported by DR DOS 5.0)
9905: {0x038, LANG_SPANISH, SUBLANG_SPANISH_CHILE}, // Chile
9906: {0x039, LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA}, // Columbia
9907: {0x03A, LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA}, // Venezuela
9908: {0x03C, LANG_MALAY, SUBLANG_MALAY_MALAYSIA}, // Malaysia
9909: {0x03D, LANG_ENGLISH, SUBLANG_ENGLISH_AUS}, // International English / Australia
9910: {0x03E, LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA}, // Indonesia / East Timor
9911: {0x03F, LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES}, // Philippines
9912: {0x040, LANG_ENGLISH, SUBLANG_ENGLISH_NZ}, // New Zealand
9913: {0x041, LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE}, // Singapore
9914: // {0x041, LANG_ENGLISH, SUBLANG_ENGLISH_SINGAPORE}, // Singapore
9915: {0x042, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan???
9916: {0x051, LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN}, // Japan (DR DOS 5.0, MS-DOS 5.0+)
9917: {0x052, LANG_KOREAN, SUBLANG_KOREAN}, // South Korea (DR DOS 5.0)
9918: {0x054, LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM}, // Vietnam
9919: {0x056, LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED}, // China (MS-DOS 5.0+)
9920: {0x058, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (MS-DOS 5.0+)
9921: {0x05A, LANG_TURKISH, SUBLANG_TURKISH_TURKEY}, // Turkey (MS-DOS 5.0+)
9922: {0x05B, LANG_HINDI, SUBLANG_HINDI_INDIA}, // India
9923: {0x05C, LANG_URDU, SUBLANG_URDU_PAKISTAN}, // Pakistan
9924: {0x05D, LANG_PASHTO, SUBLANG_PASHTO_AFGHANISTAN}, // Afghanistan
9925: // {0x05D, LANG_DARI, SUBLANG_DARI_AFGHANISTAN}, // Afghanistan
9926: {0x05E, LANG_SINHALESE, SUBLANG_SINHALESE_SRI_LANKA}, // Sri Lanka
9927: // {0x05E, LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA}, // Sri Lanka
9928: {0x062, LANG_PERSIAN, SUBLANG_PERSIAN_IRAN}, // Iran
9929: {0x070, LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS}, // Belarus
9930: {0x0C8, LANG_THAI, SUBLANG_THAI_THAILAND}, // Thailand
9931: {0x0D4, LANG_ARABIC, SUBLANG_ARABIC_MOROCCO}, // Morocco
9932: {0x0D5, LANG_ARABIC, SUBLANG_ARABIC_ALGERIA}, // Algeria
9933: {0x0D8, LANG_ARABIC, SUBLANG_ARABIC_TUNISIA}, // Tunisia
9934: {0x0DA, LANG_ARABIC, SUBLANG_ARABIC_LIBYA}, // Libya
9935: {0x0DD, LANG_WOLOF, SUBLANG_WOLOF_SENEGAL}, // Senegal
9936: // {0x0DD, LANG_PULAR, SUBLANG_PULAR_SENEGAL}, // Senegal
9937: {0x0EA, LANG_HAUSA, SUBLANG_HAUSA_NIGERIA_LATIN}, // Nigeria
9938: // {0x0EA, LANG_YORUBA, SUBLANG_YORUBA_NIGERIA}, // Nigeria
9939: // {0x0EA, LANG_IGBO, SUBLANG_IGBO_NIGERIA}, // Nigeria
9940: {0x0FB, LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA}, // Ethiopia
9941: // {0x0FB, LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA}, // Ethiopia
9942: {0x0FE, LANG_SWAHILI, SUBLANG_SWAHILI}, // Kenya
9943: {0x107, LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE}, // Zimbabwe
9944: {0x10B, LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA}, // Botswana
9945: {0x12A, LANG_FAEROESE, SUBLANG_FAEROESE_FAROE_ISLANDS}, // Faroe Islands
9946: {0x12B, LANG_GREENLANDIC, SUBLANG_GREENLANDIC_GREENLAND}, // Greenland
9947: {0x15F, LANG_PORTUGUESE, SUBLANG_PORTUGUESE}, // Portugal
9948: {0x160, LANG_LUXEMBOURGISH, SUBLANG_LUXEMBOURGISH_LUXEMBOURG}, // Luxembourg
9949: // {0x160, LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG}, // Luxembourg
9950: // {0x160, LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG}, // Luxembourg
9951: {0x161, LANG_IRISH, SUBLANG_IRISH_IRELAND}, // Ireland
9952: // {0x161, LANG_ENGLISH, SUBLANG_ENGLISH_IRELAND}, // Ireland
9953: {0x162, LANG_ICELANDIC, SUBLANG_ICELANDIC_ICELAND}, // Iceland
9954: {0x163, LANG_ALBANIAN, SUBLANG_ALBANIAN_ALBANIA}, // Albania
9955: {0x164, LANG_MALTESE, SUBLANG_MALTESE_MALTA}, // Malta
9956: {0x166, LANG_FINNISH, SUBLANG_FINNISH_FINLAND}, // Finland
9957: // {0x166, LANG_SAMI, SUBLANG_SAMI_NORTHERN_FINLAND}, // Finland
9958: // {0x166, LANG_SAMI, SUBLANG_SAMI_SKOLT_FINLAND}, // Finland
9959: // {0x166, LANG_SAMI, SUBLANG_SAMI_INARI_FINLAND}, // Finland
9960: {0x167, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria
9961: {0x172, LANG_LITHUANIAN, SUBLANG_LITHUANIAN_LITHUANIA}, // Lithuania
9962: {0x173, LANG_LATVIAN, SUBLANG_LATVIAN_LATVIA}, // Latvia
9963: {0x174, LANG_ESTONIAN, SUBLANG_ESTONIAN_ESTONIA}, // Estonia
9964: {0x17D, LANG_SERBIAN, SUBLANG_SERBIAN_LATIN}, // Serbia / Montenegro
9965: {0x180, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia???
9966: {0x181, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia
9967: {0x182, LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA}, // Slovenia
9968: {0x183, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN}, // Bosnia-Herzegovina (Latin)
9969: {0x184, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC}, // Bosnia-Herzegovina (Cyrillic)
9970: {0x185, LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA}, // FYR Macedonia
9971: {0x1A5, LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC}, // Czech Republic
9972: {0x1A6, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Slovakia
9973: {0x1F5, LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE}, // Belize
9974: {0x1F6, LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA}, // Guatemala
9975: {0x1F7, LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR}, // El Salvador
9976: {0x1F8, LANG_SPANISH, SUBLANG_SPANISH_HONDURAS}, // Honduras
9977: {0x1F9, LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA}, // Nicraragua
9978: {0x1FA, LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA}, // Costa Rica
9979: {0x1FB, LANG_SPANISH, SUBLANG_SPANISH_PANAMA}, // Panama
9980: {0x24F, LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA}, // Bolivia
1.1.1.43! root 9981: // {0x24F, LANG_QUECHUA, SUBLANG_QUECHUA_BOLIVIA}, // Bolivia
1.1.1.42 root 9982: {0x251, LANG_SPANISH, SUBLANG_SPANISH_ECUADOR}, // Ecuador
9983: // {0x251, LANG_QUECHUA, SUBLANG_QUECHUA_ECUADOR}, // Ecuador
9984: {0x253, LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY}, // Paraguay
9985: {0x256, LANG_SPANISH, SUBLANG_SPANISH_URUGUAY}, // Uruguay
9986: {0x2A1, LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM}, // Brunei Darussalam
9987: {0x311, LANG_ARABIC, SUBLANG_NEUTRAL}, // Arabic (Middle East/Saudi Arabia/etc.)
9988: {0x324, LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE}, // Ukraine
9989: {0x352, LANG_KOREAN, SUBLANG_KOREAN}, // North Korea
9990: {0x354, LANG_CHINESE, SUBLANG_CHINESE_HONGKONG}, // Hong Kong
9991: {0x355, LANG_CHINESE, SUBLANG_CHINESE_MACAU}, // Macao
9992: {0x357, LANG_KHMER, SUBLANG_KHMER_CAMBODIA}, // Cambodia
9993: {0x370, LANG_BANGLA, SUBLANG_BANGLA_BANGLADESH}, // Bangladesh
9994: {0x376, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (DOS 6.22+)
9995: {0x3C0, LANG_DIVEHI, SUBLANG_DIVEHI_MALDIVES}, // Maldives
9996: {0x3C1, LANG_ARABIC, SUBLANG_ARABIC_LEBANON}, // Lebanon
9997: {0x3C2, LANG_ARABIC, SUBLANG_ARABIC_JORDAN}, // Jordan
9998: {0x3C3, LANG_ARABIC, SUBLANG_ARABIC_SYRIA}, // Syrian Arab Republic
9999: {0x3C4, LANG_ARABIC, SUBLANG_ARABIC_IRAQ}, // Ireq
10000: {0x3C5, LANG_ARABIC, SUBLANG_ARABIC_KUWAIT}, // Kuwait
10001: {0x3C6, LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA}, // Saudi Arabia
10002: {0x3C7, LANG_ARABIC, SUBLANG_ARABIC_YEMEN}, // Yemen
10003: {0x3C8, LANG_ARABIC, SUBLANG_ARABIC_OMAN}, // Oman
10004: {0x3CB, LANG_ARABIC, SUBLANG_ARABIC_UAE}, // United Arab Emirates
10005: {0x3CC, LANG_HEBREW, SUBLANG_HEBREW_ISRAEL}, // Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+)
10006: {0x3CD, LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN}, // Bahrain
10007: {0x3CE, LANG_ARABIC, SUBLANG_ARABIC_QATAR}, // Qatar
10008: {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA}, // Mongolia
10009: // {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_PRC}, // Mongolia
10010: {0x3D1, LANG_NEPALI, SUBLANG_NEPALI_NEPAL}, // Nepal
10011: {-1, 0, 0},
10012: };
10013:
1.1.1.14 root 10014: inline void msdos_int_21h_38h()
10015: {
10016: switch(REG8(AL)) {
10017: case 0x00:
1.1.1.19 root 10018: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 10019: break;
10020: default:
1.1.1.42 root 10021: for(int i = 0;; i++) {
10022: if(country_table[i].code == (REG8(AL) != 0xff ? REG8(AL) : REG16(BX))) {
10023: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
10024: break;
10025: } else if(country_table[i].code == -1) {
10026: // 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));
10027: // REG16(AX) = 2;
10028: // m_CF = 1;
10029: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
10030: break;
10031: }
10032: }
1.1.1.14 root 10033: break;
10034: }
10035: }
10036:
1.1 root 10037: inline void msdos_int_21h_39h(int lfn)
10038: {
1.1.1.3 root 10039: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10040: REG16(AX) = errno;
1.1.1.3 root 10041: m_CF = 1;
1.1 root 10042: }
10043: }
10044:
10045: inline void msdos_int_21h_3ah(int lfn)
10046: {
1.1.1.3 root 10047: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10048: REG16(AX) = errno;
1.1.1.3 root 10049: m_CF = 1;
1.1 root 10050: }
10051: }
10052:
10053: inline void msdos_int_21h_3bh(int lfn)
10054: {
1.1.1.3 root 10055: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 10056: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 10057: m_CF = 1;
1.1 root 10058: }
10059: }
10060:
10061: inline void msdos_int_21h_3ch()
10062: {
1.1.1.3 root 10063: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10064: int attr = GetFileAttributes(path);
1.1.1.37 root 10065: int fd = -1;
1.1.1.11 root 10066: UINT16 info;
1.1.1.37 root 10067: int sio_port = 0;
10068: int lpt_port = 0;
1.1 root 10069:
1.1.1.11 root 10070: if(msdos_is_con_path(path)) {
10071: fd = _open("CON", _O_WRONLY | _O_BINARY);
10072: info = 0x80d3;
1.1.1.37 root 10073: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
1.1.1.38 root 10074: fd = _open("NUL", _O_RDWR | _O_BINARY);
1.1.1.14 root 10075: info = 0x80d3;
1.1.1.37 root 10076: msdos_set_comm_params(sio_port, path);
10077: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
10078: fd = _open("NUL", _O_WRONLY | _O_BINARY);
10079: info = 0xa8c0;
1.1.1.29 root 10080: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10081: fd = _open("NUL", _O_WRONLY | _O_BINARY);
10082: info = 0x80d3;
1.1 root 10083: } else {
10084: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 10085: info = msdos_drive_number(path);
1.1 root 10086: }
10087: if(fd != -1) {
10088: if(attr == -1) {
10089: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
10090: }
10091: SetFileAttributes(path, attr);
10092: REG16(AX) = fd;
1.1.1.37 root 10093: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 10094: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10095: } else {
10096: REG16(AX) = errno;
1.1.1.3 root 10097: m_CF = 1;
1.1 root 10098: }
10099: }
10100:
10101: inline void msdos_int_21h_3dh()
10102: {
1.1.1.3 root 10103: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10104: int mode = REG8(AL) & 0x03;
1.1.1.37 root 10105: int fd = -1;
1.1.1.11 root 10106: UINT16 info;
1.1.1.37 root 10107: int sio_port = 0;
10108: int lpt_port = 0;
1.1 root 10109:
10110: if(mode < 0x03) {
1.1.1.11 root 10111: if(msdos_is_con_path(path)) {
1.1.1.13 root 10112: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 10113: info = 0x80d3;
1.1.1.37 root 10114: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
10115: fd = msdos_open("NUL", file_mode[mode].mode);
1.1.1.14 root 10116: info = 0x80d3;
1.1.1.37 root 10117: msdos_set_comm_params(sio_port, path);
10118: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
10119: fd = _open("NUL", file_mode[mode].mode);
10120: info = 0xa8c0;
1.1.1.29 root 10121: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10122: fd = msdos_open("NUL", file_mode[mode].mode);
10123: info = 0x80d3;
1.1.1.11 root 10124: } else {
1.1.1.13 root 10125: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 10126: info = msdos_drive_number(path);
10127: }
1.1 root 10128: if(fd != -1) {
10129: REG16(AX) = fd;
1.1.1.37 root 10130: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 10131: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10132: } else {
10133: REG16(AX) = errno;
1.1.1.3 root 10134: m_CF = 1;
1.1 root 10135: }
10136: } else {
10137: REG16(AX) = 0x0c;
1.1.1.3 root 10138: m_CF = 1;
1.1 root 10139: }
10140: }
10141:
10142: inline void msdos_int_21h_3eh()
10143: {
10144: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10145: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10146:
1.1.1.20 root 10147: if(fd < process->max_files && file_handler[fd].valid) {
10148: _close(fd);
10149: msdos_file_handler_close(fd);
10150: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 10151: } else {
10152: REG16(AX) = 0x06;
1.1.1.3 root 10153: m_CF = 1;
1.1 root 10154: }
10155: }
10156:
1.1.1.35 root 10157: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID)
10158: {
10159: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
10160: int max = REG16(CX);
10161: int p = 0;
10162:
10163: while(max > p) {
10164: int chr = msdos_getch();
10165:
10166: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
10167: p = 0;
10168: buf[p++] = 0x0d;
10169: if(max > p) {
10170: buf[p++] = 0x0a;
10171: }
10172: msdos_putch(0x03);
10173: msdos_putch(0x0d);
10174: msdos_putch(0x0a);
10175: break;
10176: } else if(ctrl_break_pressed) {
10177: // skip this byte
10178: } else if(chr == 0x00) {
10179: // skip 2nd byte
10180: msdos_getch();
10181: } else if(chr == 0x0d) {
10182: // carriage return
10183: buf[p++] = 0x0d;
10184: if(max > p) {
10185: buf[p++] = 0x0a;
10186: }
10187: msdos_putch('\n');
10188: break;
10189: } else if(chr == 0x08) {
10190: // back space
10191: if(p > 0) {
10192: p--;
10193: if(msdos_ctrl_code_check(buf[p])) {
10194: msdos_putch(0x08);
10195: msdos_putch(0x08);
10196: msdos_putch(0x20);
10197: msdos_putch(0x20);
10198: msdos_putch(0x08);
10199: msdos_putch(0x08);
1.1.1.36 root 10200: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
10201: p--;
10202: msdos_putch(0x08);
10203: msdos_putch(0x08);
10204: msdos_putch(0x20);
10205: msdos_putch(0x20);
10206: msdos_putch(0x08);
10207: msdos_putch(0x08);
1.1.1.35 root 10208: } else {
10209: msdos_putch(0x08);
10210: msdos_putch(0x20);
10211: msdos_putch(0x08);
10212: }
10213: }
10214: } else if(chr == 0x1b) {
10215: // escape
10216: while(p > 0) {
10217: p--;
10218: if(msdos_ctrl_code_check(buf[p])) {
10219: msdos_putch(0x08);
10220: msdos_putch(0x08);
10221: msdos_putch(0x20);
10222: msdos_putch(0x20);
10223: msdos_putch(0x08);
10224: msdos_putch(0x08);
10225: } else {
10226: msdos_putch(0x08);
10227: msdos_putch(0x20);
10228: msdos_putch(0x08);
10229: }
10230: }
10231: } else {
10232: buf[p++] = chr;
10233: msdos_putch(chr);
10234: }
10235: }
10236: REG16(AX) = p;
10237:
10238: #ifdef USE_SERVICE_THREAD
10239: service_exit = true;
10240: #endif
10241: return(0);
10242: }
10243:
1.1 root 10244: inline void msdos_int_21h_3fh()
10245: {
10246: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10247: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10248:
1.1.1.20 root 10249: if(fd < process->max_files && file_handler[fd].valid) {
10250: if(file_mode[file_handler[fd].mode].in) {
10251: if(file_handler[fd].atty) {
1.1 root 10252: // BX is stdin or is redirected to stdin
1.1.1.35 root 10253: if(REG16(CX) != 0) {
10254: #ifdef USE_SERVICE_THREAD
10255: start_service_loop(msdos_int_21h_3fh_thread);
10256: #else
10257: msdos_int_21h_3fh_thread(NULL);
10258: REQUEST_HARDWRE_UPDATE();
10259: #endif
10260: } else {
10261: REG16(AX) = 0;
1.1 root 10262: }
10263: } else {
1.1.1.37 root 10264: REG16(AX) = msdos_read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10265: }
10266: } else {
10267: REG16(AX) = 0x05;
1.1.1.3 root 10268: m_CF = 1;
1.1 root 10269: }
10270: } else {
10271: REG16(AX) = 0x06;
1.1.1.3 root 10272: m_CF = 1;
1.1 root 10273: }
10274: }
10275:
10276: inline void msdos_int_21h_40h()
10277: {
10278: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10279: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10280:
1.1.1.20 root 10281: if(fd < process->max_files && file_handler[fd].valid) {
10282: if(file_mode[file_handler[fd].mode].out) {
1.1 root 10283: if(REG16(CX)) {
1.1.1.20 root 10284: if(file_handler[fd].atty) {
1.1 root 10285: // BX is stdout/stderr or is redirected to stdout
10286: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 10287: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 10288: }
10289: REG16(AX) = REG16(CX);
10290: } else {
1.1.1.20 root 10291: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 10292: }
10293: } else {
1.1.1.20 root 10294: UINT32 pos = _tell(fd);
10295: _lseek(fd, 0, SEEK_END);
10296: UINT32 size = _tell(fd);
1.1.1.12 root 10297: if(pos < size) {
1.1.1.20 root 10298: _lseek(fd, pos, SEEK_SET);
10299: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 10300: } else {
10301: for(UINT32 i = size; i < pos; i++) {
10302: UINT8 tmp = 0;
1.1.1.23 root 10303: msdos_write(fd, &tmp, 1);
1.1.1.12 root 10304: }
1.1.1.20 root 10305: _lseek(fd, pos, SEEK_SET);
1.1 root 10306: }
1.1.1.23 root 10307: REG16(AX) = 0;
1.1 root 10308: }
10309: } else {
10310: REG16(AX) = 0x05;
1.1.1.3 root 10311: m_CF = 1;
1.1 root 10312: }
10313: } else {
10314: REG16(AX) = 0x06;
1.1.1.3 root 10315: m_CF = 1;
1.1 root 10316: }
10317: }
10318:
10319: inline void msdos_int_21h_41h(int lfn)
10320: {
1.1.1.3 root 10321: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 10322: REG16(AX) = errno;
1.1.1.3 root 10323: m_CF = 1;
1.1 root 10324: }
10325: }
10326:
10327: inline void msdos_int_21h_42h()
10328: {
10329: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10330: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10331:
1.1.1.20 root 10332: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 10333: if(REG8(AL) < 0x03) {
1.1.1.35 root 10334: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 10335: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
10336: UINT32 pos = _tell(fd);
1.1 root 10337: REG16(AX) = pos & 0xffff;
10338: REG16(DX) = (pos >> 16);
10339: } else {
10340: REG16(AX) = 0x01;
1.1.1.3 root 10341: m_CF = 1;
1.1 root 10342: }
10343: } else {
10344: REG16(AX) = 0x06;
1.1.1.3 root 10345: m_CF = 1;
1.1 root 10346: }
10347: }
10348:
10349: inline void msdos_int_21h_43h(int lfn)
10350: {
1.1.1.3 root 10351: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 10352: int attr;
10353:
1.1.1.14 root 10354: if(!lfn && REG8(AL) > 2) {
10355: REG16(AX) = 0x01;
10356: m_CF = 1;
10357: return;
10358: }
10359: switch(REG8(lfn ? BL : AL)) {
1.1 root 10360: case 0x00:
10361: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 10362: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
10363: } else {
10364: REG16(AX) = (UINT16)GetLastError();
10365: m_CF = 1;
10366: }
10367: break;
10368: case 0x01:
10369: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
10370: REG16(AX) = (UINT16)GetLastError();
10371: m_CF = 1;
10372: }
10373: break;
10374: case 0x02:
10375: {
10376: DWORD size = GetCompressedFileSize(path, NULL);
10377: if(size != INVALID_FILE_SIZE) {
10378: if(size != 0 && size == GetFileSize(path, NULL)) {
10379: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
10380: // this isn't correct if the file is in the NTFS MFT
10381: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
10382: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
10383: }
10384: }
10385: REG16(AX) = LOWORD(size);
10386: REG16(DX) = HIWORD(size);
10387: } else {
10388: REG16(AX) = (UINT16)GetLastError();
10389: m_CF = 1;
1.1 root 10390: }
1.1.1.14 root 10391: }
10392: break;
10393: case 0x03:
10394: case 0x05:
10395: case 0x07:
10396: {
10397: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10398: if(hFile != INVALID_HANDLE_VALUE) {
10399: FILETIME local, time;
10400: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
10401: if(REG8(BL) == 7) {
10402: ULARGE_INTEGER hund;
10403: hund.LowPart = local.dwLowDateTime;
10404: hund.HighPart = local.dwHighDateTime;
10405: hund.QuadPart += REG16(SI) * 100000;
10406: local.dwLowDateTime = hund.LowPart;
10407: local.dwHighDateTime = hund.HighPart;
10408: }
10409: LocalFileTimeToFileTime(&local, &time);
10410: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
10411: REG8(BL) == 0x05 ? &time : NULL,
10412: REG8(BL) == 0x03 ? &time : NULL)) {
10413: REG16(AX) = (UINT16)GetLastError();
10414: m_CF = 1;
10415: }
10416: CloseHandle(hFile);
10417: } else {
10418: REG16(AX) = (UINT16)GetLastError();
10419: m_CF = 1;
1.1 root 10420: }
1.1.1.14 root 10421: }
10422: break;
10423: case 0x04:
10424: case 0x06:
10425: case 0x08:
10426: {
10427: WIN32_FILE_ATTRIBUTE_DATA fad;
10428: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
10429: FILETIME *time, local;
10430: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
10431: 0x06 ? &fad.ftLastAccessTime :
10432: &fad.ftCreationTime;
10433: FileTimeToLocalFileTime(time, &local);
10434: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
10435: if(REG8(BL) == 0x08) {
10436: ULARGE_INTEGER hund;
10437: hund.LowPart = local.dwLowDateTime;
10438: hund.HighPart = local.dwHighDateTime;
10439: hund.QuadPart /= 100000;
10440: REG16(SI) = (UINT16)(hund.QuadPart % 200);
10441: }
10442: } else {
10443: REG16(AX) = (UINT16)GetLastError();
10444: m_CF = 1;
1.1 root 10445: }
1.1.1.14 root 10446: }
10447: break;
1.1.1.43! root 10448: case 0xff:
! 10449: if(REG16(BP) == 0x5053) {
! 10450: if(REG8(CL) == 0x39) {
! 10451: msdos_int_21h_39h(1);
! 10452: break;
! 10453: } else if(REG8(CL) == 0x56) {
! 10454: msdos_int_21h_56h(1);
! 10455: break;
! 10456: }
! 10457: }
1.1.1.14 root 10458: default:
1.1.1.22 root 10459: 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 10460: REG16(AX) = 0x01;
10461: m_CF = 1;
10462: break;
10463: }
10464: }
10465:
10466: inline void msdos_int_21h_44h()
10467: {
1.1.1.22 root 10468: static UINT16 iteration_count = 0;
10469:
1.1.1.20 root 10470: process_t *process = msdos_process_info_get(current_psp);
10471: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
10472:
1.1.1.14 root 10473: UINT32 val = DRIVE_NO_ROOT_DIR;
10474:
10475: switch(REG8(AL)) {
10476: case 0x00:
10477: case 0x01:
10478: case 0x02:
10479: case 0x03:
10480: case 0x04:
10481: case 0x05:
10482: case 0x06:
10483: case 0x07:
1.1.1.20 root 10484: if(fd >= process->max_files || !file_handler[fd].valid) {
10485: REG16(AX) = 0x06;
10486: m_CF = 1;
10487: return;
1.1.1.14 root 10488: }
10489: break;
10490: case 0x08:
10491: case 0x09:
10492: if(REG8(BL) >= ('Z' - 'A' + 1)) {
10493: // invalid drive number
10494: REG16(AX) = 0x0f;
10495: m_CF = 1;
10496: return;
10497: } else {
10498: if(REG8(BL) == 0) {
10499: val = GetDriveType(NULL);
10500: } else {
10501: char tmp[8];
10502: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
10503: val = GetDriveType(tmp);
10504: }
10505: if(val == DRIVE_NO_ROOT_DIR) {
10506: // no drive
10507: REG16(AX) = 0x0f;
10508: m_CF = 1;
10509: return;
1.1 root 10510: }
10511: }
10512: break;
10513: }
10514: switch(REG8(AL)) {
10515: case 0x00: // get ioctrl data
1.1.1.20 root 10516: REG16(DX) = file_handler[fd].info;
1.1 root 10517: break;
10518: case 0x01: // set ioctrl data
1.1.1.20 root 10519: file_handler[fd].info |= REG8(DL);
1.1 root 10520: break;
10521: case 0x02: // recv from character device
10522: case 0x03: // send to character device
10523: case 0x04: // recv from block device
10524: case 0x05: // send to block device
10525: REG16(AX) = 0x05;
1.1.1.3 root 10526: m_CF = 1;
1.1 root 10527: break;
10528: case 0x06: // get read status
1.1.1.20 root 10529: if(file_mode[file_handler[fd].mode].in) {
10530: if(file_handler[fd].atty) {
1.1.1.14 root 10531: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 10532: } else {
1.1.1.20 root 10533: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 10534: }
1.1.1.14 root 10535: } else {
10536: REG8(AL) = 0x00;
1.1 root 10537: }
10538: break;
10539: case 0x07: // get write status
1.1.1.20 root 10540: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 10541: REG8(AL) = 0xff;
10542: } else {
10543: REG8(AL) = 0x00;
1.1 root 10544: }
10545: break;
10546: case 0x08: // check removable drive
1.1.1.14 root 10547: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
10548: // removable drive
10549: REG16(AX) = 0x00;
1.1 root 10550: } else {
1.1.1.14 root 10551: // fixed drive
10552: REG16(AX) = 0x01;
1.1 root 10553: }
10554: break;
10555: case 0x09: // check remote drive
1.1.1.14 root 10556: if(val == DRIVE_REMOTE) {
10557: // remote drive
10558: REG16(DX) = 0x1000;
1.1 root 10559: } else {
1.1.1.14 root 10560: // local drive
10561: REG16(DX) = 0x00;
1.1 root 10562: }
10563: break;
1.1.1.21 root 10564: case 0x0a: // check remote handle
10565: REG16(DX) = 0x00; // FIXME
10566: break;
1.1 root 10567: case 0x0b: // set retry count
10568: break;
1.1.1.22 root 10569: case 0x0c: // generic character device request
10570: if(REG8(CL) == 0x45) {
10571: // set iteration (retry) count
10572: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
10573: } else if(REG8(CL) == 0x4a) {
10574: // select code page
10575: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
10576: msdos_nls_tables_update();
10577: } else if(REG8(CL) == 0x65) {
10578: // get iteration (retry) count
10579: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
10580: } else if(REG8(CL) == 0x6a) {
10581: // query selected code page
10582: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
10583: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
10584:
10585: CPINFO info;
10586: GetCPInfo(active_code_page, &info);
10587:
10588: if(info.MaxCharSize != 1) {
10589: for(int i = 0;; i++) {
10590: UINT8 lo = info.LeadByte[2 * i + 0];
10591: UINT8 hi = info.LeadByte[2 * i + 1];
10592:
10593: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
10594: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
10595: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
10596:
10597: if(lo == 0 && hi == 0) {
10598: break;
10599: }
10600: }
10601: }
10602: } else if(REG8(CL) == 0x7f) {
10603: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
10604: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
10605: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
10606: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
10607: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
10608: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
10609: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
10610: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
10611: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
10612: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
10613: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
10614: } else {
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; // invalid function
10617: m_CF = 1;
10618: }
10619: break;
10620: case 0x0d: // generic block device request
10621: if(REG8(CL) == 0x40) {
10622: // set device parameters
10623: } else if(REG8(CL) == 0x46) {
10624: // set volume serial number
10625: } else if(REG8(CL) == 0x4a) {
10626: // lock logical volume
10627: } else if(REG8(CL) == 0x4b) {
10628: // lock physical volume
10629: } else if(REG8(CL) == 0x60) {
10630: // get device parameters
1.1.1.42 root 10631: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
1.1.1.22 root 10632:
1.1.1.42 root 10633: if(pcbios_update_drive_param(drive_num, 1)) {
10634: drive_param_t *drive_param = &drive_params[drive_num];
10635: DISK_GEOMETRY *geo = &drive_param->geometry;
10636:
10637: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
10638: switch(geo->MediaType) {
10639: case F5_360_512:
10640: case F5_320_512:
10641: case F5_320_1024:
10642: case F5_180_512:
10643: case F5_160_512:
10644: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
10645: break;
10646: case F5_1Pt2_512:
10647: case F3_1Pt2_512:
10648: case F3_1Pt23_1024:
10649: case F5_1Pt23_1024:
10650: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
10651: break;
10652: case F3_720_512:
10653: case F3_640_512:
10654: case F5_640_512:
10655: case F5_720_512:
10656: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
10657: break;
10658: case F8_256_128:
10659: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
10660: break;
10661: case FixedMedia:
10662: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
10663: break;
10664: case F3_1Pt44_512:
10665: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
10666: break;
10667: case F3_2Pt88_512:
10668: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
10669: break;
10670: default:
10671: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
10672: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
10673: break;
1.1.1.22 root 10674: }
1.1.1.42 root 10675: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo->MediaType == FixedMedia) ? 0x01 : 0x00;
10676: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo->Cylinders.QuadPart > 0xffff) ? 0xffff : geo->Cylinders.QuadPart;
10677: switch(geo->MediaType) {
10678: case F5_360_512:
10679: case F5_320_512:
10680: case F5_320_1024:
10681: case F5_180_512:
10682: case F5_160_512:
10683: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
10684: break;
10685: default:
10686: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
10687: break;
10688: }
10689: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo->BytesPerSector;
10690: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo->SectorsPerTrack * geo->TracksPerCylinder;
10691: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
10692: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
10693: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
10694: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
10695: switch(geo->MediaType) {
10696: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
10697: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
10698: break;
10699: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
10700: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
10701: break;
10702: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
10703: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
10704: break;
10705: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
10706: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
10707: break;
10708: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
10709: case F3_1Pt2_512:
10710: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
10711: case F5_720_512:
10712: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
10713: break;
10714: case FixedMedia: // hard disk
10715: case RemovableMedia:
10716: case Unknown:
10717: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
10718: break;
10719: default:
10720: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
10721: break;
10722: }
10723: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo->SectorsPerTrack;
10724: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
10725: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
10726: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo->TracksPerCylinder * geo->Cylinders.QuadPart;
10727: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo->Cylinders.QuadPart;
10728: // 21h BYTE device type
10729: // 22h WORD device attributes (removable or not, etc)
1.1.1.22 root 10730: } else {
10731: REG16(AX) = 0x0f; // invalid drive
10732: m_CF = 1;
10733: }
10734: } else if(REG8(CL) == 0x66) {
10735: // get volume serial number
10736: char path[] = "A:\\";
10737: char volume_label[MAX_PATH];
10738: DWORD serial_number = 0;
10739: char file_system[MAX_PATH];
10740:
10741: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
10742:
10743: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
10744: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
10745: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
10746: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
10747: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
10748: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
10749: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
10750: } else {
10751: REG16(AX) = 0x0f; // invalid drive
10752: m_CF = 1;
10753: }
10754: } else if(REG8(CL) == 0x67) {
10755: // get access flag
10756: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
10757: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
10758: } else if(REG8(CL) == 0x68) {
10759: // sense media type
1.1.1.42 root 10760: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
1.1.1.22 root 10761:
1.1.1.42 root 10762: if(pcbios_update_drive_param(drive_num, 1)) {
10763: drive_param_t *drive_param = &drive_params[drive_num];
10764: DISK_GEOMETRY *geo = &drive_param->geometry;
10765:
10766: switch(geo->MediaType) {
10767: case F3_720_512:
10768: case F5_720_512:
10769: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
10770: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
10771: break;
10772: case F3_1Pt44_512:
10773: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
10774: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
10775: break;
10776: case F3_2Pt88_512:
10777: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
10778: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
10779: break;
10780: default:
10781: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
10782: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
10783: break;
1.1.1.22 root 10784: }
10785: } else {
10786: REG16(AX) = 0x0f; // invalid drive
10787: m_CF = 1;
10788: }
10789: } else if(REG8(CL) == 0x6a) {
10790: // unlock logical volume
10791: } else if(REG8(CL) == 0x6b) {
10792: // unlock physical volume
10793: } else {
10794: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10795: REG16(AX) = 0x01; // invalid function
10796: m_CF = 1;
10797: }
10798: break;
10799: case 0x0e: // get logical drive map
10800: {
10801: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10802: if(!(GetLogicalDrives() & bits)) {
10803: REG16(AX) = 0x0f; // invalid drive
10804: m_CF = 1;
10805: } else {
10806: REG8(AL) = 0;
10807: }
10808: }
10809: break;
10810: case 0x0f: // set logical drive map
10811: {
10812: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10813: if(!(GetLogicalDrives() & bits)) {
10814: REG16(AX) = 0x0f; // invalid drive
10815: m_CF = 1;
10816: }
10817: }
10818: break;
10819: case 0x10: // query generic ioctrl capability (handle)
10820: switch(REG8(CL)) {
10821: case 0x45:
10822: case 0x4a:
10823: case 0x65:
10824: case 0x6a:
10825: case 0x7f:
10826: REG16(AX) = 0x0000; // supported
10827: break;
10828: default:
10829: REG8(AL) = 0x01; // ioctl capability not available
10830: m_CF = 1;
10831: break;
10832: }
10833: break;
10834: case 0x11: // query generic ioctrl capability (drive)
10835: switch(REG8(CL)) {
10836: case 0x40:
10837: case 0x46:
10838: case 0x4a:
10839: case 0x4b:
10840: case 0x60:
10841: case 0x66:
10842: case 0x67:
10843: case 0x68:
10844: case 0x6a:
10845: case 0x6b:
10846: REG16(AX) = 0x0000; // supported
10847: break;
10848: default:
10849: REG8(AL) = 0x01; // ioctl capability not available
10850: m_CF = 1;
10851: break;
10852: }
10853: break;
10854: case 0x12: // determine dos type
10855: case 0x51: // concurrent dos v3.2+ - installation check
10856: case 0x52: // determine dos type/get dr dos versuin
10857: REG16(AX) = 0x01; // this is not DR-DOS
10858: m_CF = 1;
10859: break;
1.1 root 10860: default:
1.1.1.22 root 10861: 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 10862: REG16(AX) = 0x01;
1.1.1.3 root 10863: m_CF = 1;
1.1 root 10864: break;
10865: }
10866: }
10867:
10868: inline void msdos_int_21h_45h()
10869: {
10870: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10871: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10872:
1.1.1.20 root 10873: if(fd < process->max_files && file_handler[fd].valid) {
10874: int dup_fd = _dup(fd);
10875: if(dup_fd != -1) {
10876: REG16(AX) = dup_fd;
10877: msdos_file_handler_dup(dup_fd, fd, current_psp);
10878: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
10879: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 10880: } else {
10881: REG16(AX) = errno;
1.1.1.3 root 10882: m_CF = 1;
1.1 root 10883: }
10884: } else {
10885: REG16(AX) = 0x06;
1.1.1.3 root 10886: m_CF = 1;
1.1 root 10887: }
10888: }
10889:
10890: inline void msdos_int_21h_46h()
10891: {
10892: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10893: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
10894: int dup_fd = REG16(CX);
10895: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 10896:
1.1.1.20 root 10897: if(REG16(BX) == REG16(CX)) {
10898: REG16(AX) = 0x06;
10899: m_CF = 1;
10900: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
10901: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
10902: _close(tmp_fd);
10903: msdos_file_handler_close(tmp_fd);
10904: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
10905: }
10906: if(_dup2(fd, dup_fd) != -1) {
10907: msdos_file_handler_dup(dup_fd, fd, current_psp);
10908: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
10909: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 10910: } else {
10911: REG16(AX) = errno;
1.1.1.3 root 10912: m_CF = 1;
1.1 root 10913: }
10914: } else {
10915: REG16(AX) = 0x06;
1.1.1.3 root 10916: m_CF = 1;
1.1 root 10917: }
10918: }
10919:
10920: inline void msdos_int_21h_47h(int lfn)
10921: {
10922: char path[MAX_PATH];
10923:
10924: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
10925: if(path[1] == ':') {
10926: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 10927: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 10928: } else {
1.1.1.3 root 10929: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 10930: }
10931: } else {
10932: REG16(AX) = errno;
1.1.1.3 root 10933: m_CF = 1;
1.1 root 10934: }
10935: }
10936:
10937: inline void msdos_int_21h_48h()
10938: {
1.1.1.19 root 10939: int seg, umb_linked;
1.1 root 10940:
1.1.1.8 root 10941: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 10942: // unlink umb not to allocate memory in umb
10943: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
10944: msdos_mem_unlink_umb();
10945: }
1.1.1.8 root 10946: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
10947: REG16(AX) = seg;
10948: } else {
10949: REG16(AX) = 0x08;
10950: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
10951: m_CF = 1;
10952: }
1.1.1.19 root 10953: if(umb_linked != 0) {
10954: msdos_mem_link_umb();
10955: }
1.1.1.8 root 10956: } else if((malloc_strategy & 0xf0) == 0x40) {
10957: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
10958: REG16(AX) = seg;
10959: } else {
10960: REG16(AX) = 0x08;
10961: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
10962: m_CF = 1;
10963: }
10964: } else if((malloc_strategy & 0xf0) == 0x80) {
10965: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
10966: REG16(AX) = seg;
10967: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
10968: REG16(AX) = seg;
10969: } else {
10970: REG16(AX) = 0x08;
10971: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
10972: m_CF = 1;
10973: }
1.1 root 10974: }
10975: }
10976:
10977: inline void msdos_int_21h_49h()
10978: {
1.1.1.14 root 10979: int mcb_seg = SREG(ES) - 1;
10980: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
10981:
10982: if(mcb->mz == 'M' || mcb->mz == 'Z') {
10983: msdos_mem_free(SREG(ES));
10984: } else {
1.1.1.33 root 10985: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 10986: m_CF = 1;
10987: }
1.1 root 10988: }
10989:
10990: inline void msdos_int_21h_4ah()
10991: {
1.1.1.14 root 10992: int mcb_seg = SREG(ES) - 1;
10993: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 10994: int max_paragraphs;
10995:
1.1.1.14 root 10996: if(mcb->mz == 'M' || mcb->mz == 'Z') {
10997: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
10998: REG16(AX) = 0x08;
10999: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
11000: m_CF = 1;
11001: }
11002: } else {
1.1.1.33 root 11003: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 11004: m_CF = 1;
1.1 root 11005: }
11006: }
11007:
11008: inline void msdos_int_21h_4bh()
11009: {
1.1.1.3 root 11010: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
11011: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 11012:
11013: switch(REG8(AL)) {
11014: case 0x00:
11015: case 0x01:
11016: if(msdos_process_exec(command, param, REG8(AL))) {
11017: REG16(AX) = 0x02;
1.1.1.3 root 11018: m_CF = 1;
1.1 root 11019: }
11020: break;
1.1.1.14 root 11021: case 0x03:
11022: {
11023: int fd;
11024: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
11025: REG16(AX) = 0x02;
11026: m_CF = 1;
11027: break;
11028: }
11029: int size = _read(fd, file_buffer, sizeof(file_buffer));
11030: _close(fd);
11031:
11032: UINT16 *overlay = (UINT16 *)param;
11033:
11034: // check exe header
11035: exe_header_t *header = (exe_header_t *)file_buffer;
11036: int header_size = 0;
11037: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
11038: header_size = header->header_size * 16;
11039: // relocation
11040: int start_seg = overlay[1];
11041: for(int i = 0; i < header->relocations; i++) {
11042: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
11043: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
11044: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
11045: }
11046: }
11047: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
11048: }
11049: break;
1.1.1.43! root 11050: case 0xfd:
! 11051: case 0xfe:
! 11052: // unknown function called in FreeCOM
! 11053: REG16(AX) = 0x01;
! 11054: m_CF = 1;
! 11055: break;
1.1 root 11056: default:
1.1.1.22 root 11057: 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 11058: REG16(AX) = 0x01;
1.1.1.3 root 11059: m_CF = 1;
1.1 root 11060: break;
11061: }
11062: }
11063:
11064: inline void msdos_int_21h_4ch()
11065: {
11066: msdos_process_terminate(current_psp, REG8(AL), 1);
11067: }
11068:
11069: inline void msdos_int_21h_4dh()
11070: {
11071: REG16(AX) = retval;
11072: }
11073:
11074: inline void msdos_int_21h_4eh()
11075: {
11076: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 11077: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
11078: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 11079: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 11080: WIN32_FIND_DATA fd;
11081:
1.1.1.14 root 11082: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
11083: find->find_magic = FIND_MAGIC;
11084: find->dta_index = dtainfo - dtalist;
1.1 root 11085: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 11086: dtainfo->allowable_mask = REG8(CL);
11087: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 11088:
1.1.1.14 root 11089: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
11090: dtainfo->allowable_mask &= ~8;
1.1 root 11091: }
1.1.1.14 root 11092: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
11093: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 11094: !msdos_find_file_has_8dot3name(&fd)) {
11095: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11096: FindClose(dtainfo->find_handle);
11097: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11098: break;
11099: }
11100: }
11101: }
1.1.1.13 root 11102: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11103: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
11104: msdos_find_file_conv_local_time(&fd);
11105: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
11106: find->size = fd.nFileSizeLow;
1.1.1.13 root 11107: strcpy(find->name, msdos_short_name(&fd));
1.1 root 11108: REG16(AX) = 0;
1.1.1.14 root 11109: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11110: find->attrib = 8;
11111: find->size = 0;
11112: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11113: dtainfo->allowable_mask &= ~8;
1.1 root 11114: REG16(AX) = 0;
11115: } else {
11116: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 11117: m_CF = 1;
1.1 root 11118: }
11119: }
11120:
11121: inline void msdos_int_21h_4fh()
11122: {
11123: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 11124: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
11125: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 11126: WIN32_FIND_DATA fd;
11127:
1.1.1.14 root 11128: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
11129: REG16(AX) = 0x12;
11130: m_CF = 1;
11131: return;
11132: }
11133: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 11134: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
11135: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 11136: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 11137: !msdos_find_file_has_8dot3name(&fd)) {
11138: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11139: FindClose(dtainfo->find_handle);
11140: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11141: break;
11142: }
11143: }
11144: } else {
1.1.1.13 root 11145: FindClose(dtainfo->find_handle);
11146: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11147: }
11148: }
1.1.1.13 root 11149: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11150: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
11151: msdos_find_file_conv_local_time(&fd);
11152: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
11153: find->size = fd.nFileSizeLow;
1.1.1.13 root 11154: strcpy(find->name, msdos_short_name(&fd));
1.1 root 11155: REG16(AX) = 0;
1.1.1.14 root 11156: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11157: find->attrib = 8;
11158: find->size = 0;
11159: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11160: dtainfo->allowable_mask &= ~8;
1.1 root 11161: REG16(AX) = 0;
11162: } else {
11163: REG16(AX) = 0x12;
1.1.1.3 root 11164: m_CF = 1;
1.1 root 11165: }
11166: }
11167:
11168: inline void msdos_int_21h_50h()
11169: {
1.1.1.8 root 11170: if(current_psp != REG16(BX)) {
11171: process_t *process = msdos_process_info_get(current_psp);
11172: if(process != NULL) {
11173: process->psp = REG16(BX);
11174: }
11175: current_psp = REG16(BX);
1.1.1.23 root 11176: msdos_sda_update(current_psp);
1.1.1.8 root 11177: }
1.1 root 11178: }
11179:
11180: inline void msdos_int_21h_51h()
11181: {
11182: REG16(BX) = current_psp;
11183: }
11184:
11185: inline void msdos_int_21h_52h()
11186: {
1.1.1.25 root 11187: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 11188: i386_load_segment_descriptor(ES);
1.1.1.25 root 11189: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 11190: }
11191:
1.1.1.43! root 11192: inline void msdos_int_21h_53h()
! 11193: {
! 11194: dpb_t *dpb = (dpb_t *)(mem + SREG_BASE(ES) + REG16(BP));
! 11195: bpb_t *bpb = (bpb_t *)(mem + SREG_BASE(DS) + REG16(SI));
! 11196:
! 11197: dpb->bytes_per_sector = bpb->bytes_per_sector;
! 11198: dpb->highest_sector_num = bpb->sectors_per_track - 1;
! 11199: dpb->shift_count = 0;
! 11200: dpb->reserved_sectors = 0;
! 11201: dpb->fat_num = bpb->fat_num;
! 11202: dpb->root_entries = bpb->root_entries;
! 11203: dpb->first_data_sector = 0;
! 11204: if(bpb->sectors_per_cluster != 0) {
! 11205: dpb->highest_cluster_num = (UINT16)(((REG16(CX) == 0x4558 && bpb->total_sectors == 0) ? bpb->ext_total_sectors : bpb->total_sectors) / bpb->sectors_per_cluster + 1);
! 11206: } else {
! 11207: dpb->highest_cluster_num = 0;
! 11208: }
! 11209: dpb->sectors_per_fat = (REG16(CX) == 0x4558 && bpb->sectors_per_fat == 0) ? bpb->ext_sectors_per_fat : bpb->sectors_per_fat;
! 11210: dpb->first_dir_sector = 0;
! 11211: dpb->device_driver_header = 0;
! 11212: dpb->media_type = bpb->media_type;
! 11213: dpb->drive_accessed = 0;
! 11214: dpb->next_dpb_ofs = 0xffff;
! 11215: dpb->next_dpb_seg = 0xffff;
! 11216: dpb->first_free_cluster = 0;
! 11217: dpb->free_clusters = 0xffff;
! 11218: }
! 11219:
1.1 root 11220: inline void msdos_int_21h_54h()
11221: {
11222: process_t *process = msdos_process_info_get(current_psp);
11223:
11224: REG8(AL) = process->verify;
11225: }
11226:
11227: inline void msdos_int_21h_55h()
11228: {
11229: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
11230:
11231: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
11232: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
11233: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
11234: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
11235: psp->parent_psp = current_psp;
11236: }
11237:
11238: inline void msdos_int_21h_56h(int lfn)
11239: {
11240: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 11241: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
11242: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 11243:
11244: if(rename(src, dst)) {
11245: REG16(AX) = errno;
1.1.1.3 root 11246: m_CF = 1;
1.1 root 11247: }
11248: }
11249:
11250: inline void msdos_int_21h_57h()
11251: {
11252: FILETIME time, local;
1.1.1.14 root 11253: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 11254: HANDLE hHandle;
1.1 root 11255:
1.1.1.21 root 11256: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 11257: REG16(AX) = (UINT16)GetLastError();
11258: m_CF = 1;
11259: return;
11260: }
11261: ctime = atime = mtime = NULL;
11262:
1.1 root 11263: switch(REG8(AL)) {
11264: case 0x00:
1.1.1.6 root 11265: case 0x01:
1.1.1.14 root 11266: mtime = &time;
1.1.1.6 root 11267: break;
11268: case 0x04:
11269: case 0x05:
1.1.1.14 root 11270: atime = &time;
1.1 root 11271: break;
1.1.1.6 root 11272: case 0x06:
11273: case 0x07:
1.1.1.14 root 11274: ctime = &time;
11275: break;
11276: default:
1.1.1.22 root 11277: 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 11278: REG16(AX) = 0x01;
11279: m_CF = 1;
11280: return;
11281: }
11282: if(REG8(AL) & 1) {
1.1 root 11283: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
11284: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 11285: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 11286: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11287: m_CF = 1;
1.1 root 11288: }
1.1.1.14 root 11289: } else {
1.1.1.21 root 11290: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 11291: // assume a device and use the current time
11292: GetSystemTimeAsFileTime(&time);
11293: }
11294: FileTimeToLocalFileTime(&time, &local);
11295: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 11296: }
11297: }
11298:
11299: inline void msdos_int_21h_58h()
11300: {
11301: switch(REG8(AL)) {
11302: case 0x00:
1.1.1.7 root 11303: REG16(AX) = malloc_strategy;
11304: break;
11305: case 0x01:
1.1.1.24 root 11306: // switch(REG16(BX)) {
11307: switch(REG8(BL)) {
1.1.1.7 root 11308: case 0x0000:
11309: case 0x0001:
11310: case 0x0002:
11311: case 0x0040:
11312: case 0x0041:
11313: case 0x0042:
11314: case 0x0080:
11315: case 0x0081:
11316: case 0x0082:
11317: malloc_strategy = REG16(BX);
1.1.1.23 root 11318: msdos_sda_update(current_psp);
1.1.1.7 root 11319: break;
11320: default:
1.1.1.22 root 11321: 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 11322: REG16(AX) = 0x01;
11323: m_CF = 1;
11324: break;
11325: }
11326: break;
11327: case 0x02:
1.1.1.19 root 11328: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 11329: break;
11330: case 0x03:
1.1.1.24 root 11331: // switch(REG16(BX)) {
11332: switch(REG8(BL)) {
1.1.1.7 root 11333: case 0x0000:
1.1.1.19 root 11334: msdos_mem_unlink_umb();
11335: break;
1.1.1.7 root 11336: case 0x0001:
1.1.1.19 root 11337: msdos_mem_link_umb();
1.1.1.7 root 11338: break;
11339: default:
1.1.1.22 root 11340: 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 11341: REG16(AX) = 0x01;
11342: m_CF = 1;
11343: break;
11344: }
1.1 root 11345: break;
11346: default:
1.1.1.22 root 11347: 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 11348: REG16(AX) = 0x01;
1.1.1.3 root 11349: m_CF = 1;
1.1 root 11350: break;
11351: }
11352: }
11353:
11354: inline void msdos_int_21h_59h()
11355: {
1.1.1.23 root 11356: sda_t *sda = (sda_t *)(mem + SDA_TOP);
11357:
11358: REG16(AX) = sda->extended_error_code;
1.1.1.43! root 11359: REG8(BL) = sda->suggested_action;
! 11360: REG8(BH) = sda->error_class;
! 11361: REG8(CL) = sda->byte_reserved_1;
! 11362: REG8(CH) = sda->locus_of_last_error;
! 11363: REG16(DX) = sda->word_reserved_1;
! 11364: REG16(SI) = sda->word_reserved_2;
! 11365: REG16(DI) = sda->last_error_pointer.w.l;
! 11366: SREG(DS) = sda->word_reserved_3;
! 11367: i386_load_segment_descriptor(DS);
! 11368: SREG(ES) = sda->last_error_pointer.w.h;
! 11369: i386_load_segment_descriptor(ES);
1.1 root 11370: }
11371:
11372: inline void msdos_int_21h_5ah()
11373: {
1.1.1.3 root 11374: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 11375: int len = strlen(path);
11376: char tmp[MAX_PATH];
11377:
11378: if(GetTempFileName(path, "TMP", 0, tmp)) {
11379: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11380:
11381: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11382: REG16(AX) = fd;
11383: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11384: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11385:
11386: strcpy(path, tmp);
11387: int dx = REG16(DX) + len;
1.1.1.3 root 11388: int ds = SREG(DS);
1.1 root 11389: while(dx > 0xffff) {
11390: dx -= 0x10;
11391: ds++;
11392: }
11393: REG16(DX) = dx;
1.1.1.3 root 11394: SREG(DS) = ds;
11395: i386_load_segment_descriptor(DS);
1.1 root 11396: } else {
11397: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11398: m_CF = 1;
1.1 root 11399: }
11400: }
11401:
11402: inline void msdos_int_21h_5bh()
11403: {
1.1.1.3 root 11404: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 11405:
1.1.1.24 root 11406: if(msdos_is_existing_file(path)) {
1.1 root 11407: // already exists
11408: REG16(AX) = 0x50;
1.1.1.3 root 11409: m_CF = 1;
1.1 root 11410: } else {
11411: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11412:
11413: if(fd != -1) {
11414: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11415: REG16(AX) = fd;
11416: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11417: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11418: } else {
11419: REG16(AX) = errno;
1.1.1.3 root 11420: m_CF = 1;
1.1 root 11421: }
11422: }
11423: }
11424:
11425: inline void msdos_int_21h_5ch()
11426: {
11427: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11428: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 11429:
1.1.1.20 root 11430: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 11431: if(REG8(AL) == 0 || REG8(AL) == 1) {
1.1.1.35 root 11432: static const int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 11433: UINT32 pos = _tell(fd);
11434: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
11435: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 11436: REG16(AX) = errno;
1.1.1.3 root 11437: m_CF = 1;
1.1 root 11438: }
1.1.1.20 root 11439: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 11440:
1.1 root 11441: // some seconds may be passed in _locking()
1.1.1.35 root 11442: REQUEST_HARDWRE_UPDATE();
1.1 root 11443: } else {
11444: REG16(AX) = 0x01;
1.1.1.3 root 11445: m_CF = 1;
1.1 root 11446: }
11447: } else {
11448: REG16(AX) = 0x06;
1.1.1.3 root 11449: m_CF = 1;
1.1 root 11450: }
11451: }
11452:
1.1.1.22 root 11453: inline void msdos_int_21h_5dh()
11454: {
11455: switch(REG8(AL)) {
11456: case 0x06: // get address of dos swappable data area
1.1.1.23 root 11457: SREG(DS) = (SDA_TOP >> 4);
11458: i386_load_segment_descriptor(DS);
11459: REG16(SI) = offsetof(sda_t, crit_error_flag);
11460: REG16(CX) = 0x80;
11461: REG16(DX) = 0x1a;
11462: break;
1.1.1.43! root 11463: case 0x0a: // set extended error information
! 11464: {
! 11465: sda_t *sda = (sda_t *)(mem + SDA_TOP);
! 11466: sda->extended_error_code = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00); // AX
! 11467: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BL
! 11468: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BH
! 11469: sda->byte_reserved_1 = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CL
! 11470: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CH
! 11471: sda->word_reserved_1 = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06); // DX
! 11472: sda->word_reserved_2 = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08); // SI
! 11473: sda->last_error_pointer.w.l = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a); // DI
! 11474: sda->word_reserved_3 = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c); // DS
! 11475: sda->last_error_pointer.w.h = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // ES
! 11476: }
! 11477: break;
1.1.1.23 root 11478: case 0x0b: // get dos swappable data areas
1.1.1.22 root 11479: REG16(AX) = 0x01;
11480: m_CF = 1;
11481: break;
11482: case 0x08: // set redirected printer mode
11483: case 0x09: // flush redirected printer output
11484: break;
11485: default:
11486: 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));
11487: REG16(AX) = 0x01;
11488: m_CF = 1;
11489: break;
11490: }
11491: }
11492:
1.1.1.42 root 11493: inline void msdos_int_21h_5eh()
11494: {
11495: switch(REG8(AL)) {
11496: case 0x00:
11497: {
11498: char name[256] = {0};
11499: DWORD dwSize = 256;
11500:
11501: if(GetComputerName(name, &dwSize)) {
11502: char *dest = (char *)(mem + SREG_BASE(DS) + REG16(DX));
11503: for(int i = 0; i < 15; i++) {
11504: dest[i] = (i < strlen(name)) ? name[i] : ' ';
11505: }
11506: dest[15] = '\0';
11507: REG8(CH) = 0x01; // nonzero valid
11508: REG8(CL) = 0x01; // NetBIOS number for machine name ???
11509: } else {
11510: REG16(AX) = 0x01;
11511: m_CF = 1;
11512: }
11513: }
11514: break;
11515: default:
11516: 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));
11517: REG16(AX) = 0x01;
11518: m_CF = 1;
11519: break;
11520: }
11521: }
11522:
1.1.1.30 root 11523: inline void msdos_int_21h_5fh()
11524: {
11525: switch(REG8(AL)) {
1.1.1.42 root 11526: case 0x05:
11527: {
11528: DWORD drives = GetLogicalDrives();
11529: UINT16 count = 0;
11530: for(int i = 0; i < 26; i++) {
11531: if(drives & (1 << i)) {
11532: char volume[] = "A:\\";
11533: volume[0] = 'A' + i;
11534: if(GetDriveType(volume) == DRIVE_REMOTE) {
11535: count++;
11536: }
11537: }
11538: }
11539: REG16(BP) = count;
11540: }
1.1.1.30 root 11541: case 0x02:
11542: {
11543: DWORD drives = GetLogicalDrives();
11544: for(int i = 0, index = 0; i < 26; i++) {
11545: if(drives & (1 << i)) {
11546: char volume[] = "A:\\";
11547: volume[0] = 'A' + i;
11548: if(GetDriveType(volume) == DRIVE_REMOTE) {
11549: if(index == REG16(BX)) {
11550: DWORD dwSize = 128;
11551: volume[2] = '\0';
11552: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
11553: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
11554: REG8(BH) = 0x00; // valid
11555: REG8(BL) = 0x04; // disk drive
1.1.1.42 root 11556: REG16(CX) = 0x00; // LANtastic
1.1.1.30 root 11557: return;
11558: }
11559: index++;
11560: }
11561: }
11562: }
11563: }
11564: REG16(AX) = 0x12; // no more files
11565: m_CF = 1;
11566: break;
11567: default:
11568: 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));
11569: REG16(AX) = 0x01;
11570: m_CF = 1;
11571: break;
11572: }
11573: }
11574:
1.1 root 11575: inline void msdos_int_21h_60h(int lfn)
11576: {
1.1.1.14 root 11577: char full[MAX_PATH], *path;
11578:
1.1 root 11579: if(lfn) {
1.1.1.14 root 11580: char *name;
11581: *full = '\0';
1.1.1.3 root 11582: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 11583: switch(REG8(CL)) {
11584: case 1:
11585: GetShortPathName(full, full, MAX_PATH);
11586: my_strupr(full);
11587: break;
11588: case 2:
11589: GetLongPathName(full, full, MAX_PATH);
11590: break;
11591: }
11592: path = full;
11593: } else {
11594: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
11595: }
11596: if(*path != '\0') {
11597: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 11598: } else {
1.1.1.14 root 11599: REG16(AX) = (UINT16)GetLastError();
11600: m_CF = 1;
1.1 root 11601: }
11602: }
11603:
11604: inline void msdos_int_21h_61h()
11605: {
11606: REG8(AL) = 0;
11607: }
11608:
11609: inline void msdos_int_21h_62h()
11610: {
11611: REG16(BX) = current_psp;
11612: }
11613:
11614: inline void msdos_int_21h_63h()
11615: {
11616: switch(REG8(AL)) {
11617: case 0x00:
1.1.1.3 root 11618: SREG(DS) = (DBCS_TABLE >> 4);
11619: i386_load_segment_descriptor(DS);
1.1 root 11620: REG16(SI) = (DBCS_TABLE & 0x0f);
11621: REG8(AL) = 0x00;
11622: break;
1.1.1.22 root 11623: case 0x01: // set korean input mode
11624: case 0x02: // get korean input mode
11625: REG8(AL) = 0xff; // not supported
11626: break;
1.1 root 11627: default:
1.1.1.22 root 11628: 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 11629: REG16(AX) = 0x01;
1.1.1.3 root 11630: m_CF = 1;
1.1 root 11631: break;
11632: }
11633: }
11634:
1.1.1.25 root 11635: UINT16 get_extended_country_info(UINT8 func)
1.1 root 11636: {
1.1.1.25 root 11637: switch(func) {
1.1.1.17 root 11638: case 0x01:
11639: if(REG16(CX) >= 5) {
1.1.1.19 root 11640: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 11641: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
11642: REG16(CX) = sizeof(data);
11643: ZeroMemory(data, sizeof(data));
11644: data[0] = 0x01;
11645: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 11646: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 11647: *(UINT16 *)(data + 5) = active_code_page;
11648: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 11649: // REG16(AX) = active_code_page;
1.1.1.17 root 11650: } else {
1.1.1.25 root 11651: return(0x08); // insufficient memory
1.1.1.17 root 11652: }
11653: break;
11654: case 0x02:
11655: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
11656: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
11657: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 11658: // REG16(AX) = active_code_page;
1.1.1.17 root 11659: REG16(CX) = 0x05;
11660: break;
1.1.1.23 root 11661: case 0x03:
11662: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
11663: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
11664: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 11665: // REG16(AX) = active_code_page;
1.1.1.23 root 11666: REG16(CX) = 0x05;
11667: break;
1.1.1.17 root 11668: case 0x04:
11669: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
11670: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
11671: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 11672: // REG16(AX) = active_code_page;
1.1.1.17 root 11673: REG16(CX) = 0x05;
11674: break;
11675: case 0x05:
11676: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
11677: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
11678: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 11679: // REG16(AX) = active_code_page;
1.1.1.17 root 11680: REG16(CX) = 0x05;
11681: break;
11682: case 0x06:
11683: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
11684: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
11685: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 11686: // REG16(AX) = active_code_page;
1.1.1.17 root 11687: REG16(CX) = 0x05;
11688: break;
1.1 root 11689: case 0x07:
1.1.1.3 root 11690: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
11691: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
11692: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 11693: // REG16(AX) = active_code_page;
1.1 root 11694: REG16(CX) = 0x05;
11695: break;
1.1.1.25 root 11696: default:
11697: return(0x01); // function number invalid
11698: }
11699: return(0x00);
11700: }
11701:
11702: inline void msdos_int_21h_65h()
11703: {
11704: char tmp[0x10000];
11705:
11706: switch(REG8(AL)) {
1.1.1.43! root 11707: case 0x00:
! 11708: if(REG16(CX) >= 7) {
! 11709: set_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), REG16(CX) - 7);
! 11710: REG16(AX) = system_code_page;
! 11711: } else {
! 11712: REG16(AX) = 0x0c;
! 11713: m_CF = 1;
! 11714: }
! 11715: break;
1.1.1.25 root 11716: case 0x01:
11717: case 0x02:
11718: case 0x03:
11719: case 0x04:
11720: case 0x05:
11721: case 0x06:
11722: case 0x07:
11723: {
11724: UINT16 result = get_extended_country_info(REG8(AL));
11725: if(result) {
11726: REG16(AX) = result;
11727: m_CF = 1;
11728: } else {
11729: REG16(AX) = active_code_page; // FIXME: is this correct???
11730: }
11731: }
11732: break;
1.1 root 11733: case 0x20:
1.1.1.25 root 11734: case 0xa0:
1.1.1.19 root 11735: memset(tmp, 0, sizeof(tmp));
11736: tmp[0] = REG8(DL);
1.1 root 11737: my_strupr(tmp);
11738: REG8(DL) = tmp[0];
11739: break;
11740: case 0x21:
1.1.1.25 root 11741: case 0xa1:
1.1 root 11742: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 11743: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 11744: my_strupr(tmp);
1.1.1.3 root 11745: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 11746: break;
11747: case 0x22:
1.1.1.25 root 11748: case 0xa2:
1.1.1.3 root 11749: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 11750: break;
1.1.1.25 root 11751: case 0x23:
11752: // FIXME: need to check multi-byte (kanji) charactre?
11753: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
11754: // 8278h/8299h: multi-byte (kanji) Y and y
11755: REG16(AX) = 0x00;
11756: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
11757: // 826dh/828eh: multi-byte (kanji) N and n
11758: REG16(AX) = 0x01;
11759: } else {
11760: REG16(AX) = 0x02;
11761: }
11762: break;
1.1 root 11763: default:
1.1.1.22 root 11764: 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 11765: REG16(AX) = 0x01;
1.1.1.3 root 11766: m_CF = 1;
1.1 root 11767: break;
11768: }
11769: }
11770:
11771: inline void msdos_int_21h_66h()
11772: {
11773: switch(REG8(AL)) {
11774: case 0x01:
11775: REG16(BX) = active_code_page;
11776: REG16(DX) = system_code_page;
11777: break;
11778: case 0x02:
11779: if(active_code_page == REG16(BX)) {
11780: REG16(AX) = 0xeb41;
11781: } else if(_setmbcp(REG16(BX)) == 0) {
11782: active_code_page = REG16(BX);
1.1.1.17 root 11783: msdos_nls_tables_update();
1.1 root 11784: REG16(AX) = 0xeb41;
1.1.1.32 root 11785: SetConsoleCP(active_code_page);
11786: SetConsoleOutputCP(active_code_page);
1.1 root 11787: } else {
11788: REG16(AX) = 0x25;
1.1.1.3 root 11789: m_CF = 1;
1.1 root 11790: }
11791: break;
11792: default:
1.1.1.22 root 11793: 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 11794: REG16(AX) = 0x01;
1.1.1.3 root 11795: m_CF = 1;
1.1 root 11796: break;
11797: }
11798: }
11799:
11800: inline void msdos_int_21h_67h()
11801: {
11802: process_t *process = msdos_process_info_get(current_psp);
11803:
11804: if(REG16(BX) <= MAX_FILES) {
11805: process->max_files = max(REG16(BX), 20);
11806: } else {
11807: REG16(AX) = 0x08;
1.1.1.3 root 11808: m_CF = 1;
1.1 root 11809: }
11810: }
11811:
11812: inline void msdos_int_21h_68h()
11813: {
11814: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11815: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 11816:
1.1.1.20 root 11817: if(fd < process->max_files && file_handler[fd].valid) {
11818: // fflush(_fdopen(fd, ""));
1.1 root 11819: } else {
11820: REG16(AX) = 0x06;
1.1.1.3 root 11821: m_CF = 1;
1.1 root 11822: }
11823: }
11824:
11825: inline void msdos_int_21h_69h()
11826: {
1.1.1.3 root 11827: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 11828: char path[] = "A:\\";
11829: char volume_label[MAX_PATH];
11830: DWORD serial_number = 0;
11831: char file_system[MAX_PATH];
11832:
11833: if(REG8(BL) == 0) {
11834: path[0] = 'A' + _getdrive() - 1;
11835: } else {
11836: path[0] = 'A' + REG8(BL) - 1;
11837: }
11838:
11839: switch(REG8(AL)) {
11840: case 0x00:
11841: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
11842: info->info_level = 0;
11843: info->serial_number = serial_number;
11844: memset(info->volume_label, 0x20, 11);
11845: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
11846: memset(info->file_system, 0x20, 8);
11847: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
11848: } else {
11849: REG16(AX) = errno;
1.1.1.3 root 11850: m_CF = 1;
1.1 root 11851: }
11852: break;
11853: case 0x01:
11854: REG16(AX) = 0x03;
1.1.1.3 root 11855: m_CF = 1;
1.1 root 11856: }
11857: }
11858:
11859: inline void msdos_int_21h_6ah()
11860: {
11861: REG8(AH) = 0x68;
11862: msdos_int_21h_68h();
11863: }
11864:
11865: inline void msdos_int_21h_6bh()
11866: {
11867: REG8(AL) = 0;
11868: }
11869:
11870: inline void msdos_int_21h_6ch(int lfn)
11871: {
1.1.1.3 root 11872: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 11873: int mode = REG8(BL) & 0x03;
11874:
11875: if(mode < 0x03) {
1.1.1.29 root 11876: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 11877: // file exists
11878: if(REG8(DL) & 1) {
1.1.1.37 root 11879: int fd = -1;
1.1.1.11 root 11880: UINT16 info;
1.1.1.37 root 11881: int sio_port = 0;
11882: int lpt_port = 0;
1.1 root 11883:
1.1.1.11 root 11884: if(msdos_is_con_path(path)) {
1.1.1.13 root 11885: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 11886: info = 0x80d3;
1.1.1.37 root 11887: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
11888: fd = msdos_open("NUL", file_mode[mode].mode);
1.1.1.14 root 11889: info = 0x80d3;
1.1.1.37 root 11890: msdos_set_comm_params(sio_port, path);
11891: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
11892: fd = msdos_open("NUL", file_mode[mode].mode);
11893: info = 0xa8c0;
1.1.1.29 root 11894: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 11895: fd = msdos_open("NUL", file_mode[mode].mode);
11896: info = 0x80d3;
1.1.1.11 root 11897: } else {
1.1.1.13 root 11898: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 11899: info = msdos_drive_number(path);
11900: }
1.1 root 11901: if(fd != -1) {
11902: REG16(AX) = fd;
11903: REG16(CX) = 1;
1.1.1.37 root 11904: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 11905: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11906: } else {
11907: REG16(AX) = errno;
1.1.1.3 root 11908: m_CF = 1;
1.1 root 11909: }
11910: } else if(REG8(DL) & 2) {
11911: int attr = GetFileAttributes(path);
1.1.1.37 root 11912: int fd = -1;
1.1.1.11 root 11913: UINT16 info;
1.1.1.37 root 11914: int sio_port = 0;
11915: int lpt_port = 0;
1.1 root 11916:
1.1.1.11 root 11917: if(msdos_is_con_path(path)) {
1.1.1.13 root 11918: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 11919: info = 0x80d3;
1.1.1.37 root 11920: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
11921: fd = msdos_open("NUL", file_mode[mode].mode);
1.1.1.14 root 11922: info = 0x80d3;
1.1.1.37 root 11923: msdos_set_comm_params(sio_port, path);
11924: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
11925: fd = msdos_open("NUL", file_mode[mode].mode);
11926: info = 0xa8c0;
1.1.1.29 root 11927: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 11928: fd = msdos_open("NUL", file_mode[mode].mode);
11929: info = 0x80d3;
1.1 root 11930: } else {
11931: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 11932: info = msdos_drive_number(path);
1.1 root 11933: }
11934: if(fd != -1) {
11935: if(attr == -1) {
11936: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
11937: }
11938: SetFileAttributes(path, attr);
11939: REG16(AX) = fd;
11940: REG16(CX) = 3;
1.1.1.37 root 11941: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 11942: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11943: } else {
11944: REG16(AX) = errno;
1.1.1.3 root 11945: m_CF = 1;
1.1 root 11946: }
11947: } else {
11948: REG16(AX) = 0x50;
1.1.1.3 root 11949: m_CF = 1;
1.1 root 11950: }
11951: } else {
11952: // file not exists
11953: if(REG8(DL) & 0x10) {
11954: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11955:
11956: if(fd != -1) {
11957: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11958: REG16(AX) = fd;
11959: REG16(CX) = 2;
11960: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11961: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11962: } else {
11963: REG16(AX) = errno;
1.1.1.3 root 11964: m_CF = 1;
1.1 root 11965: }
11966: } else {
11967: REG16(AX) = 0x02;
1.1.1.3 root 11968: m_CF = 1;
1.1 root 11969: }
11970: }
11971: } else {
11972: REG16(AX) = 0x0c;
1.1.1.3 root 11973: m_CF = 1;
1.1 root 11974: }
11975: }
11976:
1.1.1.43! root 11977: inline void msdos_int_21h_70h()
! 11978: {
! 11979: switch(REG8(AL)) {
! 11980: case 0x02:
! 11981: if(REG16(CX) >= 7) {
! 11982: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5);
! 11983: msdos_nls_tables_update();
! 11984: set_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(SI) + 7), REG16(CX) - 7);
! 11985: REG16(AX) = system_code_page;
! 11986: } else {
! 11987: REG16(AX) = 0x0c;
! 11988: m_CF = 1;
! 11989: }
! 11990: break;
! 11991: default:
! 11992: 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));
! 11993: REG16(AX) = 0x01;
! 11994: m_CF = 1;
! 11995: break;
! 11996: }
! 11997: }
! 11998:
1.1 root 11999: inline void msdos_int_21h_710dh()
12000: {
12001: // reset drive
12002: }
12003:
1.1.1.17 root 12004: inline void msdos_int_21h_7141h(int lfn)
12005: {
12006: if(REG16(SI) == 0) {
12007: msdos_int_21h_41h(lfn);
12008: return;
12009: }
12010: if(REG16(SI) != 1) {
12011: REG16(AX) = 5;
12012: m_CF = 1;
12013: }
12014: /* wild card and matching attributes... */
12015: char tmp[MAX_PATH * 2];
12016: // copy search pathname (and quick check overrun)
12017: ZeroMemory(tmp, sizeof(tmp));
12018: tmp[MAX_PATH - 1] = '\0';
12019: tmp[MAX_PATH] = 1;
12020: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
12021:
12022: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
12023: REG16(AX) = 1;
12024: m_CF = 1;
12025: return;
12026: }
12027: for(char *s = tmp; *s; ++s) {
12028: if(*s == '/') {
12029: *s = '\\';
12030: }
12031: }
12032: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
12033: if(tmp_name) {
12034: ++tmp_name;
12035: } else {
12036: tmp_name = strchr(tmp, ':');
12037: tmp_name = tmp_name ? tmp_name + 1 : tmp;
12038: }
12039:
12040: WIN32_FIND_DATAA fd;
12041: HANDLE fh = FindFirstFileA(tmp, &fd);
12042: if(fh == INVALID_HANDLE_VALUE) {
12043: REG16(AX) = 2;
12044: m_CF = 1;
12045: return;
12046: }
12047: do {
12048: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
12049: strcpy(tmp_name, fd.cFileName);
12050: if(remove(msdos_trimmed_path(tmp, lfn))) {
12051: REG16(AX) = 5;
12052: m_CF = 1;
12053: break;
12054: }
12055: }
12056: } while(FindNextFileA(fh, &fd));
12057: if(!m_CF) {
12058: if(GetLastError() != ERROR_NO_MORE_FILES) {
12059: m_CF = 1;
12060: REG16(AX) = 2;
12061: }
12062: }
12063: FindClose(fh);
12064: }
12065:
1.1 root 12066: inline void msdos_int_21h_714eh()
12067: {
12068: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 12069: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
12070: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12071: WIN32_FIND_DATA fd;
12072:
1.1.1.13 root 12073: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
12074: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12075: FindClose(dtainfo->find_handle);
12076: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12077: }
12078: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 12079: dtainfo->allowable_mask = REG8(CL);
12080: dtainfo->required_mask = REG8(CH);
12081: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 12082:
1.1.1.14 root 12083: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
12084: dtainfo->allowable_mask &= ~8;
1.1 root 12085: }
1.1.1.14 root 12086: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
12087: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 12088: if(!FindNextFile(dtainfo->find_handle, &fd)) {
12089: FindClose(dtainfo->find_handle);
12090: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12091: break;
12092: }
12093: }
12094: }
1.1.1.13 root 12095: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 12096: find->attrib = fd.dwFileAttributes;
12097: msdos_find_file_conv_local_time(&fd);
12098: if(REG16(SI) == 0) {
12099: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
12100: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
12101: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
12102: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
12103: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
12104: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
12105: } else {
12106: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
12107: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
12108: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
12109: }
12110: find->size_hi = fd.nFileSizeHigh;
12111: find->size_lo = fd.nFileSizeLow;
12112: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 12113: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 12114: REG16(AX) = dtainfo - dtalist + 1;
12115: } else if(dtainfo->allowable_mask & 8) {
1.1 root 12116: // volume label
12117: find->attrib = 8;
12118: find->size_hi = find->size_lo = 0;
12119: strcpy(find->full_name, process->volume_label);
12120: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 12121: dtainfo->allowable_mask &= ~8;
12122: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 12123: } else {
12124: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 12125: m_CF = 1;
1.1 root 12126: }
12127: }
12128:
12129: inline void msdos_int_21h_714fh()
12130: {
12131: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 12132: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 12133: WIN32_FIND_DATA fd;
12134:
1.1.1.14 root 12135: if(REG16(BX) - 1u >= MAX_DTAINFO) {
12136: REG16(AX) = 6;
1.1.1.13 root 12137: m_CF = 1;
12138: return;
12139: }
1.1.1.14 root 12140: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 12141: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12142: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 12143: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 12144: if(!FindNextFile(dtainfo->find_handle, &fd)) {
12145: FindClose(dtainfo->find_handle);
12146: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12147: break;
12148: }
12149: }
12150: } else {
1.1.1.13 root 12151: FindClose(dtainfo->find_handle);
12152: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12153: }
12154: }
1.1.1.13 root 12155: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 12156: find->attrib = fd.dwFileAttributes;
12157: msdos_find_file_conv_local_time(&fd);
12158: if(REG16(SI) == 0) {
12159: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
12160: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
12161: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
12162: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
12163: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
12164: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
12165: } else {
12166: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
12167: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
12168: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
12169: }
12170: find->size_hi = fd.nFileSizeHigh;
12171: find->size_lo = fd.nFileSizeLow;
12172: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 12173: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 12174: } else if(dtainfo->allowable_mask & 8) {
1.1 root 12175: // volume label
12176: find->attrib = 8;
12177: find->size_hi = find->size_lo = 0;
12178: strcpy(find->full_name, process->volume_label);
12179: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 12180: dtainfo->allowable_mask &= ~8;
1.1 root 12181: } else {
12182: REG16(AX) = 0x12;
1.1.1.3 root 12183: m_CF = 1;
1.1 root 12184: }
12185: }
12186:
12187: inline void msdos_int_21h_71a0h()
12188: {
12189: DWORD max_component_len, file_sys_flag;
12190:
1.1.1.14 root 12191: 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))) {
12192: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
12193: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 12194: REG16(CX) = (UINT16)max_component_len; // 255
12195: REG16(DX) = (UINT16)max_component_len + 5; // 260
12196: } else {
12197: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12198: m_CF = 1;
1.1 root 12199: }
12200: }
12201:
12202: inline void msdos_int_21h_71a1h()
12203: {
1.1.1.14 root 12204: if(REG16(BX) - 1u >= MAX_DTAINFO) {
12205: REG16(AX) = 6;
1.1.1.13 root 12206: m_CF = 1;
12207: return;
12208: }
1.1.1.14 root 12209: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 12210: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
12211: FindClose(dtainfo->find_handle);
12212: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 12213: }
12214: }
12215:
12216: inline void msdos_int_21h_71a6h()
12217: {
12218: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 12219: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12220:
1.1.1.3 root 12221: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 12222: struct _stat64 status;
12223: DWORD serial_number = 0;
12224:
1.1.1.20 root 12225: if(fd < process->max_files && file_handler[fd].valid) {
12226: if(_fstat64(fd, &status) == 0) {
12227: if(file_handler[fd].path[1] == ':') {
1.1 root 12228: // NOTE: we need to consider the network file path "\\host\share\"
12229: char volume[] = "A:\\";
1.1.1.20 root 12230: volume[0] = file_handler[fd].path[1];
1.1 root 12231: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
12232: }
1.1.1.20 root 12233: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 12234: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
12235: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
12236: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
12237: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
12238: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
12239: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
12240: *(UINT32 *)(buffer + 0x1c) = serial_number;
12241: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
12242: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
12243: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 12244: // this is dummy id and it will be changed when it is reopened...
1.1 root 12245: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 12246: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 12247: } else {
12248: REG16(AX) = errno;
1.1.1.3 root 12249: m_CF = 1;
1.1 root 12250: }
12251: } else {
12252: REG16(AX) = 0x06;
1.1.1.3 root 12253: m_CF = 1;
1.1 root 12254: }
12255: }
12256:
12257: inline void msdos_int_21h_71a7h()
12258: {
12259: switch(REG8(BL)) {
12260: case 0x00:
1.1.1.3 root 12261: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 12262: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12263: m_CF = 1;
1.1 root 12264: }
12265: break;
12266: case 0x01:
12267: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 12268: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 12269: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 12270: m_CF = 1;
1.1 root 12271: }
12272: break;
12273: default:
1.1.1.22 root 12274: 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 12275: REG16(AX) = 0x01;
1.1.1.3 root 12276: m_CF = 1;
1.1 root 12277: break;
12278: }
12279: }
12280:
12281: inline void msdos_int_21h_71a8h()
12282: {
12283: if(REG8(DH) == 0) {
12284: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 12285: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 12286: memset(fcb, 0x20, sizeof(fcb));
12287: int len = strlen(tmp);
1.1.1.21 root 12288: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 12289: if(tmp[i] == '.') {
12290: pos = 8;
12291: } else {
12292: if(msdos_lead_byte_check(tmp[i])) {
12293: fcb[pos++] = tmp[i++];
12294: }
12295: fcb[pos++] = tmp[i];
12296: }
12297: }
1.1.1.3 root 12298: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 12299: } else {
1.1.1.3 root 12300: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 12301: }
12302: }
12303:
1.1.1.22 root 12304: inline void msdos_int_21h_71aah()
12305: {
12306: char drv[] = "A:", path[MAX_PATH];
12307: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
12308:
12309: if(REG8(BL) == 0) {
12310: drv[0] = 'A' + _getdrive() - 1;
12311: } else {
12312: drv[0] = 'A' + REG8(BL) - 1;
12313: }
12314: switch(REG8(BH)) {
12315: case 0x00:
12316: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
12317: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
12318: if(GetLogicalDrives() & bits) {
12319: REG16(AX) = 0x0f; // invalid drive
12320: } else {
12321: REG16(AX) = 0x03; // path not found
12322: }
12323: m_CF = 1;
12324: }
12325: break;
12326: case 0x01:
12327: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
12328: REG16(AX) = 0x0f; // invalid drive
12329: m_CF = 1;
12330: }
12331: break;
12332: case 0x02:
12333: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
12334: REG16(AX) = 0x0f; // invalid drive
12335: m_CF = 1;
12336: } else if(strncmp(path, "\\??\\", 4) != 0) {
12337: REG16(AX) = 0x0f; // invalid drive
12338: m_CF = 1;
12339: } else {
12340: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
12341: }
12342: break;
12343: default:
12344: 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));
12345: REG16(AX) = 0x01;
12346: m_CF = 1;
12347: break;
12348: }
12349: }
12350:
1.1.1.14 root 12351: inline void msdos_int_21h_7300h()
12352: {
12353: if(REG8(AL) == 0) {
12354: REG8(AL) = REG8(CL);
12355: REG8(AH) = 0;
12356: } else {
12357: REG16(AX) = 0x01;
12358: m_CF = 1;
12359: }
12360: }
12361:
12362: inline void msdos_int_21h_7302h()
12363: {
12364: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
12365: UINT16 seg, ofs;
12366:
12367: if(REG16(CX) < 0x3f) {
12368: REG8(AL) = 0x18;
12369: m_CF = 1;
12370: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
12371: REG8(AL) = 0xff;
12372: m_CF = 1;
12373: } else {
12374: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
12375: }
12376: }
12377:
1.1 root 12378: inline void msdos_int_21h_7303h()
12379: {
1.1.1.3 root 12380: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
12381: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 12382: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
12383:
12384: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
12385: info->size_of_structure = sizeof(ext_space_info_t);
12386: info->structure_version = 0;
12387: info->sectors_per_cluster = sectors_per_cluster;
12388: info->bytes_per_sector = bytes_per_sector;
12389: info->available_clusters_on_drive = free_clusters;
12390: info->total_clusters_on_drive = total_clusters;
12391: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
12392: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
12393: info->available_allocation_units = free_clusters; // ???
12394: info->total_allocation_units = total_clusters; // ???
12395: } else {
12396: REG16(AX) = errno;
1.1.1.3 root 12397: m_CF = 1;
1.1 root 12398: }
12399: }
12400:
1.1.1.30 root 12401: inline void msdos_int_21h_dbh()
12402: {
12403: // Novell NetWare - Workstation - Get Number of Local Drives
12404: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
12405: REG8(AL) = dos_info->last_drive;
12406: }
12407:
12408: inline void msdos_int_21h_dch()
12409: {
12410: // Novell NetWare - Connection Services - Get Connection Number
12411: REG8(AL) = 0x00;
12412: }
12413:
1.1.1.32 root 12414: inline void msdos_int_24h()
12415: {
12416: const char *message = NULL;
12417: int key = 0;
12418:
12419: for(int i = 0; i < array_length(critical_error_table); i++) {
12420: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
12421: if(active_code_page == 932) {
12422: message = critical_error_table[i].message_japanese;
12423: }
12424: if(message == NULL) {
12425: message = critical_error_table[i].message_english;
12426: }
12427: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
12428: strcpy((char *)(mem + WORK_TOP + 1), message);
12429:
12430: SREG(ES) = WORK_TOP >> 4;
12431: i386_load_segment_descriptor(ES);
12432: REG16(DI) = 0x0000;
12433: break;
12434: }
12435: }
12436: fprintf(stderr, "\n%s", message);
12437: if(!(REG8(AH) & 0x80)) {
12438: if(REG8(AH) & 0x01) {
12439: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
12440: } else {
12441: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
12442: }
12443: }
12444: fprintf(stderr, "\n");
12445:
1.1.1.33 root 12446: {
1.1.1.32 root 12447: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
1.1.1.33 root 12448: }
1.1.1.32 root 12449: if(REG8(AH) & 0x10) {
12450: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
12451: }
12452: if(REG8(AH) & 0x20) {
12453: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
12454: }
12455: if(REG8(AH) & 0x08) {
12456: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
12457: }
12458: fprintf(stderr, "? ");
12459:
12460: while(1) {
12461: while(!_kbhit()) {
12462: Sleep(10);
12463: }
12464: key = _getch();
12465:
12466: if(key == 'I' || key == 'i') {
12467: if(REG8(AH) & 0x20) {
12468: REG8(AL) = 0;
12469: break;
12470: }
12471: } else if(key == 'R' || key == 'r') {
12472: if(REG8(AH) & 0x10) {
12473: REG8(AL) = 1;
12474: break;
12475: }
12476: } else if(key == 'A' || key == 'a') {
12477: REG8(AL) = 2;
12478: break;
12479: } else if(key == 'F' || key == 'f') {
12480: if(REG8(AH) & 0x08) {
12481: REG8(AL) = 3;
12482: break;
12483: }
12484: }
12485: }
12486: fprintf(stderr, "%c\n", key);
12487: }
12488:
1.1 root 12489: inline void msdos_int_25h()
12490: {
12491: UINT16 seg, ofs;
12492: DWORD dwSize;
12493:
1.1.1.3 root 12494: #if defined(HAS_I386)
12495: I386OP(pushf)();
12496: #else
12497: PREFIX86(_pushf());
12498: #endif
1.1 root 12499:
12500: if(!(REG8(AL) < 26)) {
12501: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 12502: m_CF = 1;
1.1 root 12503: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
12504: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12505: m_CF = 1;
1.1 root 12506: } else {
12507: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
12508: char dev[64];
12509: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
12510:
12511: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
12512: if(hFile == INVALID_HANDLE_VALUE) {
12513: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12514: m_CF = 1;
1.1 root 12515: } else {
1.1.1.19 root 12516: UINT32 top_sector = REG16(DX);
12517: UINT16 sector_num = REG16(CX);
12518: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
12519:
12520: if(sector_num == 0xffff) {
12521: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
12522: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
12523: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
12524: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
12525: buffer_addr = (seg << 4) + ofs;
12526: }
12527: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
12528: // REG8(AL) = 0x02; // drive not ready
12529: // m_CF = 1;
12530: // } else
12531: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 12532: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 12533: m_CF = 1;
1.1.1.19 root 12534: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 12535: REG8(AL) = 0x0b; // read error
1.1.1.3 root 12536: m_CF = 1;
1.1 root 12537: }
12538: CloseHandle(hFile);
12539: }
12540: }
12541: }
12542:
12543: inline void msdos_int_26h()
12544: {
1.1.1.42 root 12545: // this operation may cause serious damage for drives, so support only floppy disk...
1.1 root 12546: UINT16 seg, ofs;
12547: DWORD dwSize;
12548:
1.1.1.3 root 12549: #if defined(HAS_I386)
12550: I386OP(pushf)();
12551: #else
12552: PREFIX86(_pushf());
12553: #endif
1.1 root 12554:
12555: if(!(REG8(AL) < 26)) {
12556: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 12557: m_CF = 1;
1.1 root 12558: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
12559: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12560: m_CF = 1;
1.1 root 12561: } else {
12562: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
12563: char dev[64];
12564: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
12565:
12566: if(dpb->media_type == 0xf8) {
12567: // this drive is not a floppy
1.1.1.6 root 12568: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
12569: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
12570: // }
1.1 root 12571: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12572: m_CF = 1;
1.1 root 12573: } else {
12574: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
12575: if(hFile == INVALID_HANDLE_VALUE) {
12576: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12577: m_CF = 1;
1.1 root 12578: } else {
1.1.1.19 root 12579: UINT32 top_sector = REG16(DX);
12580: UINT16 sector_num = REG16(CX);
12581: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
12582:
12583: if(sector_num == 0xffff) {
12584: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
12585: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
12586: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
12587: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
12588: buffer_addr = (seg << 4) + ofs;
12589: }
1.1 root 12590: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
12591: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 12592: m_CF = 1;
1.1.1.19 root 12593: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 12594: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 12595: m_CF = 1;
1.1.1.19 root 12596: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 12597: REG8(AL) = 0x0a; // write error
1.1.1.3 root 12598: m_CF = 1;
1.1 root 12599: }
12600: CloseHandle(hFile);
12601: }
12602: }
12603: }
12604: }
12605:
12606: inline void msdos_int_27h()
12607: {
1.1.1.29 root 12608: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
12609: try {
12610: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
12611: } catch(...) {
12612: // recover the broken mcb
12613: int mcb_seg = SREG(CS) - 1;
12614: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 12615:
1.1.1.29 root 12616: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 12617: mcb->mz = 'M';
12618: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
12619:
1.1.1.29 root 12620: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 12621: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 12622: } else {
1.1.1.39 root 12623: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 12624: }
12625: } else {
12626: mcb->mz = 'Z';
1.1.1.30 root 12627: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 12628: }
12629: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
12630: }
1.1.1.3 root 12631: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 12632: }
12633:
12634: inline void msdos_int_29h()
12635: {
1.1.1.14 root 12636: #if 1
12637: // need to check escape sequences
1.1 root 12638: msdos_putch(REG8(AL));
1.1.1.14 root 12639: #else
12640: DWORD num;
12641: vram_flush();
1.1.1.23 root 12642: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 12643: cursor_moved = true;
12644: #endif
1.1 root 12645: }
12646:
12647: inline void msdos_int_2eh()
12648: {
12649: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
12650: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 12651: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 12652: char *token = my_strtok(tmp, " ");
12653: strcpy(command, token);
12654: strcpy(opt, token + strlen(token) + 1);
12655:
12656: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
12657: param->env_seg = 0;
12658: param->cmd_line.w.l = 44;
12659: param->cmd_line.w.h = (WORK_TOP >> 4);
12660: param->fcb1.w.l = 24;
12661: param->fcb1.w.h = (WORK_TOP >> 4);
12662: param->fcb2.w.l = 24;
12663: param->fcb2.w.h = (WORK_TOP >> 4);
12664:
12665: memset(mem + WORK_TOP + 24, 0x20, 20);
12666:
12667: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
12668: cmd_line->len = strlen(opt);
12669: strcpy(cmd_line->cmd, opt);
12670: cmd_line->cmd[cmd_line->len] = 0x0d;
12671:
1.1.1.28 root 12672: try {
12673: if(msdos_process_exec(command, param, 0)) {
12674: REG16(AX) = 0xffff; // error before processing command
12675: } else {
12676: // set flag to set retval to ax when the started process is terminated
12677: process_t *process = msdos_process_info_get(current_psp);
12678: process->called_by_int2eh = true;
12679: }
12680: } catch(...) {
12681: REG16(AX) = 0xffff; // error before processing command
12682: }
1.1 root 12683: }
12684:
1.1.1.29 root 12685: inline void msdos_int_2fh_05h()
12686: {
12687: switch(REG8(AL)) {
12688: case 0x00:
1.1.1.32 root 12689: REG8(AL) = 0xff;
12690: break;
12691: case 0x01:
12692: case 0x02:
12693: for(int i = 0; i < array_length(standard_error_table); i++) {
12694: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
12695: const char *message = NULL;
12696: if(active_code_page == 932) {
12697: message = standard_error_table[i].message_japanese;
12698: }
12699: if(message == NULL) {
12700: message = standard_error_table[i].message_english;
12701: }
12702: strcpy((char *)(mem + WORK_TOP), message);
12703:
12704: SREG(ES) = WORK_TOP >> 4;
12705: i386_load_segment_descriptor(ES);
12706: REG16(DI) = 0x0000;
12707: REG8(AL) = 0x01;
12708: break;
12709: }
12710: }
1.1.1.29 root 12711: break;
12712: default:
12713: 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));
12714: m_CF = 1;
12715: }
12716: }
12717:
1.1.1.22 root 12718: inline void msdos_int_2fh_11h()
12719: {
12720: switch(REG8(AL)) {
12721: case 0x00:
1.1.1.29 root 12722: if(i386_read_stack() == 0xdada) {
12723: // MSCDEX is not installed
12724: // REG8(AL) = 0x00;
12725: } else {
12726: // Network Redirector is not installed
12727: // REG8(AL) = 0x00;
12728: }
1.1.1.22 root 12729: break;
12730: default:
1.1.1.43! root 12731: // 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 12732: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 12733: m_CF = 1;
12734: break;
12735: }
12736: }
12737:
1.1.1.21 root 12738: inline void msdos_int_2fh_12h()
12739: {
12740: switch(REG8(AL)) {
1.1.1.22 root 12741: case 0x00:
1.1.1.29 root 12742: // DOS 3.0+ internal functions are installed
1.1.1.22 root 12743: REG8(AL) = 0xff;
12744: break;
1.1.1.29 root 12745: // case 0x01: // DOS 3.0+ internal - Close Current File
12746: case 0x02:
12747: {
12748: UINT16 stack = i386_read_stack();
12749: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
12750: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
12751: i386_load_segment_descriptor(ES);
12752: }
12753: break;
1.1.1.30 root 12754: case 0x03:
12755: SREG(DS) = (DEVICE_TOP >> 4);
12756: i386_load_segment_descriptor(DS);
12757: break;
1.1.1.29 root 12758: case 0x04:
12759: {
12760: UINT16 stack = i386_read_stack();
12761: REG8(AL) = (stack == '/') ? '\\' : stack;
12762: #if defined(HAS_I386)
12763: m_ZF = (REG8(AL) == '\\');
12764: #else
12765: m_ZeroVal = (REG8(AL) != '\\');
12766: #endif
12767: }
12768: break;
12769: case 0x05:
12770: msdos_putch(i386_read_stack());
12771: break;
12772: // case 0x06: // DOS 3.0+ internal - Invole Critical Error
12773: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
12774: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
12775: // case 0x09: // DOS 3.0+ internal - Flush and FREE Disk Buffer
12776: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
12777: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
12778: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
12779: case 0x0d:
12780: {
12781: SYSTEMTIME time;
12782: FILETIME file_time;
12783: WORD dos_date, dos_time;
12784: GetLocalTime(&time);
12785: SystemTimeToFileTime(&time, &file_time);
12786: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
12787: REG16(AX) = dos_date;
12788: REG16(DX) = dos_time;
12789: }
12790: break;
12791: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
12792: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
12793: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
12794: case 0x11:
12795: {
12796: char path[MAX_PATH], *p;
12797: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
12798: my_strupr(path);
12799: while((p = my_strchr(path, '/')) != NULL) {
12800: *p = '\\';
12801: }
12802: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
12803: }
12804: break;
12805: case 0x12:
12806: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
12807: break;
12808: case 0x13:
12809: {
12810: char tmp[2] = {0};
12811: tmp[0] = i386_read_stack();
12812: my_strupr(tmp);
12813: REG8(AL) = tmp[0];
12814: }
12815: break;
12816: case 0x14:
12817: #if defined(HAS_I386)
12818: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
12819: #else
12820: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
12821: #endif
12822: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
12823: break;
12824: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 12825: case 0x16:
12826: if(REG16(BX) < 20) {
12827: SREG(ES) = SFT_TOP >> 4;
12828: i386_load_segment_descriptor(ES);
12829: REG16(DI) = 6 + 0x3b * REG16(BX);
12830:
12831: // update system file table
12832: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
12833: if(file_handler[REG16(BX)].valid) {
12834: int count = 0;
12835: for(int i = 0; i < 20; i++) {
12836: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
12837: count++;
12838: }
12839: }
12840: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
12841: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
12842: _lseek(REG16(BX), 0, SEEK_END);
12843: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
12844: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
12845: } else {
12846: memset(sft, 0, 0x3b);
12847: }
12848: } else {
12849: REG16(AX) = 0x06;
12850: m_CF = 1;
12851: }
12852: break;
1.1.1.29 root 12853: // case 0x17: // DOS 3.0+ internal - Get Current Directory Structure for Drive
12854: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
12855: // case 0x19: // DOS 3.0+ internal - Set Drive???
12856: case 0x1a:
12857: {
12858: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
12859: if(path[1] == ':') {
12860: if(path[0] >= 'a' && path[0] <= 'z') {
12861: REG8(AL) = path[0] - 'a' + 1;
12862: } else if(path[0] >= 'A' && path[0] <= 'Z') {
12863: REG8(AL) = path[0] - 'A' + 1;
12864: } else {
12865: REG8(AL) = 0xff; // invalid
12866: }
12867: strcpy(full, path);
12868: strcpy(path, full + 2);
12869: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
12870: if(full[0] >= 'a' && full[0] <= 'z') {
12871: REG8(AL) = full[0] - 'a' + 1;
12872: } else if(full[0] >= 'A' && full[0] <= 'Z') {
12873: REG8(AL) = full[0] - 'A' + 1;
12874: } else {
12875: REG8(AL) = 0xff; // invalid
12876: }
12877: } else {
12878: REG8(AL) = 0x00; // default
12879: }
12880: }
12881: break;
12882: case 0x1b:
12883: {
12884: int year = REG16(CX) + 1980;
12885: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
12886: }
12887: break;
12888: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
12889: // case 0x1d: // DOS 3.0+ internal - Sum Memory
12890: case 0x1e:
12891: {
12892: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
12893: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
12894: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
12895: #if defined(HAS_I386)
12896: m_ZF = (strcmp(full_1st, full_2nd) == 0);
12897: #else
12898: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
12899: #endif
12900: } else {
12901: #if defined(HAS_I386)
12902: m_ZF = (strcmp(path_1st, path_2nd) == 0);
12903: #else
12904: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
12905: #endif
12906: }
12907: }
12908: break;
12909: // case 0x1f: // DOS 3.0+ internal - Build Current Directory Structure
1.1.1.21 root 12910: case 0x20:
12911: {
12912: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12913:
12914: if(fd < 20) {
12915: SREG(ES) = current_psp;
12916: i386_load_segment_descriptor(ES);
12917: REG16(DI) = offsetof(psp_t, file_table) + fd;
12918: } else {
12919: REG16(AX) = 0x06;
12920: m_CF = 1;
12921: }
12922: }
12923: break;
1.1.1.29 root 12924: case 0x21:
12925: msdos_int_21h_60h(0);
12926: break;
12927: // case 0x22: // DOS 3.0+ internal - Set Extended Error Info
12928: // case 0x23: // DOS 3.0+ internal - Check If Character Device
12929: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
12930: case 0x25:
12931: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
12932: break;
12933: case 0x26:
12934: REG8(AL) = REG8(CL);
12935: msdos_int_21h_3dh();
12936: break;
12937: case 0x27:
12938: msdos_int_21h_3eh();
12939: break;
12940: case 0x28:
12941: REG16(AX) = REG16(BP);
12942: msdos_int_21h_42h();
12943: break;
12944: case 0x29:
12945: msdos_int_21h_3fh();
12946: break;
12947: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
12948: case 0x2b:
12949: REG16(AX) = REG16(BP);
12950: msdos_int_21h_44h();
12951: break;
12952: case 0x2c:
12953: REG16(BX) = DEVICE_TOP >> 4;
12954: REG16(AX) = 22;
12955: break;
12956: case 0x2d:
12957: {
12958: sda_t *sda = (sda_t *)(mem + SDA_TOP);
12959: REG16(AX) = sda->extended_error_code;
12960: }
12961: break;
12962: case 0x2e:
12963: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32 root 12964: SREG(ES) = 0x0001;
12965: i386_load_segment_descriptor(ES);
12966: REG16(DI) = 0x00;
12967: } else if(REG8(DL) == 0x08) {
12968: // dummy parameter error message read routine is at fffd:0010
12969: SREG(ES) = 0xfffd;
1.1.1.22 root 12970: i386_load_segment_descriptor(ES);
1.1.1.32 root 12971: REG16(DI) = 0x0010;
1.1.1.22 root 12972: }
12973: break;
1.1.1.29 root 12974: case 0x2f:
12975: if(REG16(DX) != 0) {
1.1.1.30 root 12976: dos_major_version = REG8(DL);
12977: dos_minor_version = REG8(DH);
1.1.1.29 root 12978: } else {
12979: REG8(DL) = 7;
12980: REG8(DH) = 10;
12981: }
12982: break;
12983: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
12984: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 12985: default:
12986: 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));
12987: REG16(AX) = 0x01;
12988: m_CF = 1;
12989: break;
12990: }
12991: }
12992:
1.1.1.30 root 12993: inline void msdos_int_2fh_13h()
12994: {
12995: static UINT16 prevDS = 0, prevDX = 0;
12996: static UINT16 prevES = 0, prevBX = 0;
12997: UINT16 tmp;
12998:
12999: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
13000: i386_load_segment_descriptor(DS);
13001: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
13002:
13003: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
13004: i386_load_segment_descriptor(ES);
13005: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
13006: }
13007:
1.1.1.22 root 13008: inline void msdos_int_2fh_14h()
13009: {
13010: switch(REG8(AL)) {
13011: case 0x00:
1.1.1.29 root 13012: // NLSFUNC.COM is installed
13013: REG8(AL) = 0xff;
1.1.1.25 root 13014: break;
13015: case 0x01:
13016: case 0x03:
13017: REG8(AL) = 0x00;
13018: active_code_page = REG16(BX);
13019: msdos_nls_tables_update();
13020: break;
13021: case 0x02:
13022: REG8(AL) = get_extended_country_info(REG16(BP));
13023: break;
13024: case 0x04:
1.1.1.42 root 13025: for(int i = 0;; i++) {
13026: if(country_table[i].code == REG16(DX)) {
13027: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage);
13028: break;
13029: } else if(country_table[i].code == -1) {
13030: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
13031: break;
13032: }
13033: }
1.1.1.25 root 13034: REG8(AL) = 0x00;
1.1.1.22 root 13035: break;
13036: default:
13037: 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));
13038: REG16(AX) = 0x01;
13039: m_CF = 1;
13040: break;
13041: }
13042: }
13043:
13044: inline void msdos_int_2fh_15h()
13045: {
13046: switch(REG8(AL)) {
1.1.1.29 root 13047: case 0x00: // CD-ROM - Installation Check
13048: if(REG16(BX) == 0x0000) {
1.1.1.43! root 13049: #if 0
! 13050: // MSCDEX is installed
! 13051: DWORD dwDrives = GetLogicalDrives();
! 13052: REG16(BX) = 0;
! 13053: for(int i = 0, n = 0; i < 26; i++) {
! 13054: if(dwDrives & (1 << i)) {
! 13055: char volume[] = "A:\\";
! 13056: volume[0] = 'A' + i;
! 13057: if(GetDriveType(volume) == DRIVE_CDROM) {
! 13058: if(REG16(BX) == 0) {
! 13059: REG16(CX) = i;
! 13060: }
! 13061: REG16(BX)++;
! 13062: }
! 13063: }
! 13064: }
! 13065: #else
1.1.1.29 root 13066: // MSCDEX is not installed
13067: // REG8(AL) = 0x00;
1.1.1.43! root 13068: #endif
1.1.1.29 root 13069: } else {
13070: // GRAPHICS.COM is not installed
13071: // REG8(AL) = 0x00;
13072: }
1.1.1.22 root 13073: break;
1.1.1.43! root 13074: case 0x0b:
! 13075: // this function is called in DOSSHELL
! 13076: {
! 13077: char volume[] = "A:\\";
! 13078: volume[0] = 'A' + REG8(CL);
! 13079: REG16(AX) = (GetDriveType(volume) == DRIVE_CDROM) ? 0x5ad8 : 0x0000;
! 13080: REG16(BX) = 0xadad;
! 13081: }
! 13082: break;
! 13083: case 0x0d:
! 13084: {
! 13085: DWORD dwDrives = GetLogicalDrives();
! 13086: for(int i = 0, n = 0; i < 26; i++) {
! 13087: if(dwDrives & (1 << i)) {
! 13088: char volume[] = "A:\\";
! 13089: volume[0] = 'A' + i;
! 13090: if(GetDriveType(volume) == DRIVE_CDROM) {
! 13091: mem[SREG_BASE(ES) + REG16(BX) + (n++)] = i;
! 13092: }
! 13093: }
! 13094: }
! 13095: }
! 13096: break;
1.1.1.22 root 13097: case 0xff:
1.1.1.29 root 13098: if(REG16(BX) == 0x0000) {
13099: // CORELCDX is not installed
13100: } else {
13101: 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));
13102: REG16(AX) = 0x01;
13103: m_CF = 1;
13104: }
1.1.1.22 root 13105: break;
1.1.1.21 root 13106: default:
1.1.1.22 root 13107: 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 13108: REG16(AX) = 0x01;
13109: m_CF = 1;
13110: break;
13111: }
13112: }
13113:
1.1 root 13114: inline void msdos_int_2fh_16h()
13115: {
13116: switch(REG8(AL)) {
13117: case 0x00:
1.1.1.14 root 13118: if(no_windows) {
1.1.1.29 root 13119: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
13120: // REG8(AL) = 0x00;
1.1.1.14 root 13121: } else {
1.1.1.30 root 13122: REG8(AL) = win_major_version;
13123: REG8(AH) = win_minor_version;
1.1 root 13124: }
13125: break;
1.1.1.43! root 13126: case 0x05: // Windows Enhanced Mode & 286 DOSX Init Broadcast
1.1.1.30 root 13127: // from DOSBox
13128: i386_set_a20_line(1);
13129: break;
1.1.1.43! root 13130: case 0x06: // Windows Enhanced Mode & 286 DOSX exit Broadcast
! 13131: case 0x08: // Windows Enhanced Mode Init Complete Broadcast
! 13132: case 0x09: // Windows Enhanced Mode Begin Exit Broadcast
! 13133: break;
! 13134: case 0x07:
! 13135: // Virtual Device Call API
! 13136: break;
1.1.1.22 root 13137: case 0x0a:
13138: if(!no_windows) {
13139: REG16(AX) = 0x0000;
1.1.1.30 root 13140: REG8(BH) = win_major_version;
13141: REG8(BL) = win_minor_version;
1.1.1.22 root 13142: REG16(CX) = 0x0003; // enhanced
13143: }
13144: break;
1.1.1.30 root 13145: case 0x0b:
13146: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 13147: case 0x0e:
13148: case 0x0f:
1.1.1.30 root 13149: case 0x10:
1.1.1.22 root 13150: case 0x11:
13151: case 0x12:
13152: case 0x13:
13153: case 0x14:
1.1.1.30 root 13154: case 0x15:
1.1.1.43! root 13155: case 0x81:
! 13156: case 0x82:
1.1.1.33 root 13157: case 0x86:
1.1.1.22 root 13158: case 0x87:
1.1.1.30 root 13159: case 0x89:
1.1.1.33 root 13160: case 0x8a:
1.1.1.22 root 13161: // function not supported, do not clear AX
13162: break;
1.1.1.14 root 13163: case 0x80:
13164: Sleep(10);
1.1.1.35 root 13165: REQUEST_HARDWRE_UPDATE();
1.1.1.29 root 13166: REG8(AL) = 0x00;
1.1.1.14 root 13167: break;
1.1.1.33 root 13168: case 0x83:
13169: REG16(BX) = 0x01; // system vm id
13170: break;
1.1.1.22 root 13171: case 0x8e:
13172: REG16(AX) = 0x00; // failed
13173: break;
1.1.1.20 root 13174: case 0x8f:
13175: switch(REG8(DH)) {
13176: case 0x00:
13177: case 0x02:
13178: case 0x03:
13179: REG16(AX) = 0x00;
13180: break;
13181: case 0x01:
13182: REG16(AX) = 0x168f;
13183: break;
13184: }
13185: break;
1.1 root 13186: default:
1.1.1.22 root 13187: 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));
13188: REG16(AX) = 0x01;
13189: m_CF = 1;
13190: break;
13191: }
13192: }
13193:
13194: inline void msdos_int_2fh_19h()
13195: {
13196: switch(REG8(AL)) {
13197: case 0x00:
1.1.1.29 root 13198: // SHELLB.COM is not installed
13199: // REG8(AL) = 0x00;
1.1.1.22 root 13200: break;
13201: case 0x01:
13202: case 0x02:
13203: case 0x03:
13204: case 0x04:
13205: REG16(AX) = 0x01;
13206: m_CF = 1;
13207: break;
1.1.1.29 root 13208: case 0x80:
13209: // IBM ROM-DOS v4.0 is not installed
13210: // REG8(AL) = 0x00;
13211: break;
1.1.1.22 root 13212: default:
13213: 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 13214: REG16(AX) = 0x01;
1.1.1.3 root 13215: m_CF = 1;
1.1 root 13216: break;
13217: }
13218: }
13219:
13220: inline void msdos_int_2fh_1ah()
13221: {
13222: switch(REG8(AL)) {
13223: case 0x00:
1.1.1.29 root 13224: // ANSI.SYS is installed
1.1 root 13225: REG8(AL) = 0xff;
13226: break;
13227: default:
1.1.1.22 root 13228: 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));
13229: REG16(AX) = 0x01;
13230: m_CF = 1;
13231: break;
13232: }
13233: }
13234:
1.1.1.30 root 13235: inline void msdos_int_2fh_40h()
1.1.1.22 root 13236: {
13237: switch(REG8(AL)) {
13238: case 0x00:
1.1.1.30 root 13239: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
13240: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 13241: break;
1.1.1.43! root 13242: case 0x10:
! 13243: // OS/2 v2.0+ - Installation Check
! 13244: REG16(AX) = 0x01;
! 13245: m_CF = 1;
! 13246: break;
1.1.1.22 root 13247: default:
13248: 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 13249: REG16(AX) = 0x01;
1.1.1.3 root 13250: m_CF = 1;
1.1 root 13251: break;
13252: }
13253: }
13254:
13255: inline void msdos_int_2fh_43h()
13256: {
13257: switch(REG8(AL)) {
13258: case 0x00:
1.1.1.29 root 13259: // XMS is installed ?
1.1.1.19 root 13260: #ifdef SUPPORT_XMS
13261: if(support_xms) {
13262: REG8(AL) = 0x80;
13263: } else
13264: #endif
13265: REG8(AL) = 0x00;
13266: break;
13267: case 0x10:
13268: SREG(ES) = XMS_TOP >> 4;
13269: i386_load_segment_descriptor(ES);
1.1.1.26 root 13270: REG16(BX) = 0x15;
1.1 root 13271: break;
13272: default:
1.1.1.22 root 13273: 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));
13274: REG16(AX) = 0x01;
13275: m_CF = 1;
13276: break;
13277: }
13278: }
13279:
13280: inline void msdos_int_2fh_46h()
13281: {
13282: switch(REG8(AL)) {
13283: case 0x80:
1.1.1.29 root 13284: // Windows v3.0 is not installed
13285: // REG8(AL) = 0x00;
1.1.1.22 root 13286: break;
13287: default:
13288: 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));
13289: REG16(AX) = 0x01;
13290: m_CF = 1;
13291: break;
13292: }
13293: }
13294:
13295: inline void msdos_int_2fh_48h()
13296: {
13297: switch(REG8(AL)) {
13298: case 0x00:
1.1.1.29 root 13299: // DOSKEY is not installed
13300: // REG8(AL) = 0x00;
1.1.1.22 root 13301: break;
13302: case 0x10:
13303: msdos_int_21h_0ah();
13304: REG16(AX) = 0x00;
13305: break;
13306: default:
13307: 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 13308: REG16(AX) = 0x01;
1.1.1.3 root 13309: m_CF = 1;
1.1 root 13310: break;
13311: }
13312: }
13313:
13314: inline void msdos_int_2fh_4ah()
13315: {
13316: switch(REG8(AL)) {
1.1.1.29 root 13317: #ifdef SUPPORT_HMA
13318: case 0x01: // DOS 5.0+ - Query Free HMA Space
13319: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
13320: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13321: // restore first free mcb in high memory area
13322: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13323: }
13324: int offset = 0xffff;
13325: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
13326: REG16(DI) = offset + 0x10;
13327: } else {
13328: REG16(DI) = 0xffff;
13329: }
13330: } else {
13331: // HMA is already used
13332: REG16(BX) = 0;
13333: REG16(DI) = 0xffff;
13334: }
13335: SREG(ES) = 0xffff;
13336: i386_load_segment_descriptor(ES);
13337: break;
13338: case 0x02: // DOS 5.0+ - Allocate HMA Space
13339: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
13340: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13341: // restore first free mcb in high memory area
13342: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13343: }
13344: int size = REG16(BX), offset;
13345: if((size % 16) != 0) {
13346: size &= ~15;
13347: size += 16;
13348: }
13349: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
13350: REG16(BX) = size;
13351: REG16(DI) = offset + 0x10;
13352: is_hma_used_by_int_2fh = true;
13353: } else {
13354: REG16(BX) = 0;
13355: REG16(DI) = 0xffff;
13356: }
13357: } else {
13358: // HMA is already used
13359: REG16(BX) = 0;
13360: REG16(DI) = 0xffff;
13361: }
13362: SREG(ES) = 0xffff;
13363: i386_load_segment_descriptor(ES);
13364: break;
13365: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
13366: if(REG8(DL) == 0x00) {
13367: if(!is_hma_used_by_xms) {
13368: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13369: // restore first free mcb in high memory area
13370: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13371: is_hma_used_by_int_2fh = false;
13372: }
13373: int size = REG16(BX), offset;
13374: if((size % 16) != 0) {
13375: size &= ~15;
13376: size += 16;
13377: }
13378: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
13379: // REG16(BX) = size;
13380: SREG(ES) = 0xffff;
13381: i386_load_segment_descriptor(ES);
13382: REG16(DI) = offset + 0x10;
13383: is_hma_used_by_int_2fh = true;
13384: } else {
13385: REG16(DI) = 0xffff;
13386: }
13387: } else {
13388: REG16(DI) = 0xffff;
13389: }
13390: } else if(REG8(DL) == 0x01) {
13391: if(!is_hma_used_by_xms) {
13392: int size = REG16(BX);
13393: if((size % 16) != 0) {
13394: size &= ~15;
13395: size += 16;
13396: }
13397: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
13398: // memory block address is not changed
13399: } else {
13400: REG16(DI) = 0xffff;
13401: }
13402: } else {
13403: REG16(DI) = 0xffff;
13404: }
13405: } else if(REG8(DL) == 0x02) {
13406: if(!is_hma_used_by_xms) {
13407: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13408: // restore first free mcb in high memory area
13409: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13410: is_hma_used_by_int_2fh = false;
13411: } else {
13412: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
13413: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
13414: is_hma_used_by_int_2fh = false;
13415: }
13416: }
13417: }
13418: } else {
13419: 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));
13420: REG16(AX) = 0x01;
13421: m_CF = 1;
13422: }
13423: break;
13424: case 0x04: // Windows95 - Get Start of HMA Memory Chain
13425: if(!is_hma_used_by_xms) {
13426: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
13427: // restore first free mcb in high memory area
13428: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13429: is_hma_used_by_int_2fh = false;
13430: }
13431: REG16(AX) = 0x0000;
13432: SREG(ES) = 0xffff;
13433: i386_load_segment_descriptor(ES);
13434: REG16(DI) = 0x10;
13435: }
13436: break;
13437: #else
1.1 root 13438: case 0x01:
13439: case 0x02:
1.1.1.29 root 13440: // HMA is already used
1.1.1.27 root 13441: REG16(BX) = 0x0000;
1.1.1.3 root 13442: SREG(ES) = 0xffff;
13443: i386_load_segment_descriptor(ES);
1.1 root 13444: REG16(DI) = 0xffff;
13445: break;
1.1.1.19 root 13446: case 0x03:
13447: // unable to allocate
13448: REG16(DI) = 0xffff;
13449: break;
13450: case 0x04:
13451: // function not supported, do not clear AX
13452: break;
1.1.1.29 root 13453: #endif
13454: case 0x10:
1.1.1.42 root 13455: switch(REG16(BX)) {
13456: case 0x0000:
13457: case 0x0001:
13458: case 0x0002:
13459: case 0x0003:
13460: case 0x0004:
13461: case 0x0005:
13462: case 0x0006:
13463: case 0x0007:
13464: case 0x0008:
13465: case 0x000a:
13466: case 0x1234:
13467: // SMARTDRV v4.00+ is not installed
13468: break;
13469: default:
1.1.1.29 root 13470: 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));
13471: REG16(AX) = 0x01;
13472: m_CF = 1;
1.1.1.42 root 13473: break;
1.1.1.29 root 13474: }
13475: break;
13476: case 0x11:
1.1.1.42 root 13477: switch(REG16(BX)) {
13478: case 0x0000:
13479: case 0x0001:
13480: case 0x0002:
13481: case 0x0003:
13482: case 0x0004:
13483: case 0x0005:
13484: case 0x0006:
13485: case 0x0007:
13486: case 0x0008:
13487: case 0x0009:
13488: case 0x000a:
13489: case 0x000b:
13490: case 0xfffe:
13491: case 0xffff:
1.1.1.29 root 13492: // DBLSPACE.BIN is not installed
1.1.1.42 root 13493: break;
13494: default:
13495: 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));
13496: REG16(AX) = 0x01;
13497: m_CF = 1;
13498: break;
13499: }
13500: break;
13501: case 0x12:
13502: if(REG16(CX) == 0x4d52 && REG16(DX) == 0x4349) {
13503: // Microsoft Realtime Compression Interface (MRCI) is not installed
13504: } else if(REG16(CX) == 0x5354 && REG16(DX) == 0x4143) {
13505: // Stacker 4 LZS Compression Interface (LZSAPI) is not installed
1.1.1.29 root 13506: } else {
13507: 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));
13508: REG16(AX) = 0x01;
13509: m_CF = 1;
13510: }
1.1.1.22 root 13511: break;
1.1.1.42 root 13512: case 0x13:
13513: // DBLSPACE.BIN is not installed
13514: break;
1.1.1.22 root 13515: default:
13516: 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));
13517: REG16(AX) = 0x01;
13518: m_CF = 1;
13519: break;
13520: }
13521: }
13522:
13523: inline void msdos_int_2fh_4bh()
13524: {
13525: switch(REG8(AL)) {
1.1.1.24 root 13526: case 0x01:
1.1.1.22 root 13527: case 0x02:
1.1.1.29 root 13528: // Task Switcher is not installed
1.1.1.24 root 13529: break;
13530: case 0x03:
13531: // this call is available from within DOSSHELL even if the task switcher is not installed
13532: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 13533: break;
1.1.1.30 root 13534: case 0x04:
13535: REG16(BX) = 0x0000; // free switcher id successfully
13536: break;
1.1.1.43! root 13537: case 0x05:
! 13538: REG16(BX) = 0x0000; // no instance data chain
! 13539: SREG(ES) = 0x0000;
! 13540: i386_load_segment_descriptor(ES);
! 13541: break;
1.1 root 13542: default:
1.1.1.22 root 13543: 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 13544: REG16(AX) = 0x01;
1.1.1.3 root 13545: m_CF = 1;
1.1 root 13546: break;
13547: }
13548: }
13549:
13550: inline void msdos_int_2fh_4fh()
13551: {
13552: switch(REG8(AL)) {
13553: case 0x00:
1.1.1.29 root 13554: // BILING is installed
1.1.1.27 root 13555: REG16(AX) = 0x0000;
13556: REG8(DL) = 0x01; // major version
13557: REG8(DH) = 0x00; // minor version
1.1 root 13558: break;
13559: case 0x01:
1.1.1.27 root 13560: REG16(AX) = 0x0000;
1.1 root 13561: REG16(BX) = active_code_page;
13562: break;
13563: default:
1.1.1.22 root 13564: 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));
13565: REG16(AX) = 0x01;
13566: m_CF = 1;
13567: break;
13568: }
13569: }
13570:
13571: inline void msdos_int_2fh_55h()
13572: {
13573: switch(REG8(AL)) {
13574: case 0x00:
13575: case 0x01:
13576: // 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));
13577: break;
13578: default:
13579: 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 13580: REG16(AX) = 0x01;
1.1.1.3 root 13581: m_CF = 1;
1.1 root 13582: break;
13583: }
13584: }
13585:
1.1.1.24 root 13586: inline void msdos_int_2fh_adh()
13587: {
13588: switch(REG8(AL)) {
13589: case 0x00:
1.1.1.29 root 13590: // DISPLAY.SYS is installed
1.1.1.24 root 13591: REG8(AL) = 0xff;
13592: REG16(BX) = 0x100; // ???
13593: break;
13594: case 0x01:
13595: active_code_page = REG16(BX);
13596: msdos_nls_tables_update();
13597: REG16(AX) = 0x01;
13598: break;
13599: case 0x02:
13600: REG16(BX) = active_code_page;
13601: break;
13602: case 0x03:
13603: // FIXME
13604: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
13605: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
13606: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
13607: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
13608: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
13609: break;
13610: case 0x80:
13611: break; // keyb.com is not installed
13612: default:
13613: 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));
13614: REG16(AX) = 0x01;
13615: m_CF = 1;
13616: break;
13617: }
13618: }
13619:
1.1 root 13620: inline void msdos_int_2fh_aeh()
13621: {
13622: switch(REG8(AL)) {
13623: case 0x00:
1.1.1.28 root 13624: // FIXME: we need to check the given command line
13625: REG8(AL) = 0x00; // the command should be executed as usual
13626: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 13627: break;
13628: case 0x01:
13629: {
13630: char command[MAX_PATH];
13631: memset(command, 0, sizeof(command));
1.1.1.3 root 13632: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 13633:
13634: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
13635: param->env_seg = 0;
13636: param->cmd_line.w.l = 44;
13637: param->cmd_line.w.h = (WORK_TOP >> 4);
13638: param->fcb1.w.l = 24;
13639: param->fcb1.w.h = (WORK_TOP >> 4);
13640: param->fcb2.w.l = 24;
13641: param->fcb2.w.h = (WORK_TOP >> 4);
13642:
13643: memset(mem + WORK_TOP + 24, 0x20, 20);
13644:
13645: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 13646: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
13647: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 13648: cmd_line->cmd[cmd_line->len] = 0x0d;
13649:
1.1.1.28 root 13650: try {
13651: msdos_process_exec(command, param, 0);
13652: } catch(...) {
13653: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 13654: }
13655: }
13656: break;
13657: default:
1.1.1.22 root 13658: 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 13659: REG16(AX) = 0x01;
1.1.1.3 root 13660: m_CF = 1;
1.1 root 13661: break;
13662: }
13663: }
13664:
1.1.1.34 root 13665: inline void msdos_int_2fh_b7h()
13666: {
13667: switch(REG8(AL)) {
13668: case 0x00:
13669: // APPEND is not installed
13670: // REG8(AL) = 0x00;
13671: break;
13672: case 0x07:
1.1.1.43! root 13673: case 0x11:
1.1.1.34 root 13674: // COMMAND.COM calls this service without checking APPEND is installed
13675: break;
13676: default:
13677: 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));
13678: REG16(AX) = 0x01;
13679: m_CF = 1;
13680: break;
13681: }
13682: }
13683:
1.1.1.24 root 13684: inline void msdos_int_33h_0000h()
13685: {
13686: REG16(AX) = 0xffff; // hardware/driver installed
13687: REG16(BX) = MAX_MOUSE_BUTTONS;
13688: }
13689:
13690: inline void msdos_int_33h_0001h()
13691: {
1.1.1.34 root 13692: if(mouse.hidden > 0) {
13693: mouse.hidden--;
13694: }
13695: if(mouse.hidden == 0) {
1.1.1.24 root 13696: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
13697: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
13698: }
13699: pic[1].imr &= ~0x10; // enable irq12
13700: }
13701: }
13702:
13703: inline void msdos_int_33h_0002h()
13704: {
1.1.1.34 root 13705: mouse.hidden++;
13706: // SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode & ~ENABLE_MOUSE_INPUT);
13707: pic[1].imr |= 0x10; // enable irq12
1.1.1.24 root 13708: }
13709:
13710: inline void msdos_int_33h_0003h()
13711: {
1.1.1.34 root 13712: // if(mouse.hidden > 0) {
13713: update_console_input();
13714: // }
1.1.1.24 root 13715: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 13716: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
13717: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
13718: }
13719:
13720: inline void msdos_int_33h_0004h()
13721: {
13722: mouse.position.x = REG16(CX);
13723: mouse.position.x = REG16(DX);
1.1.1.24 root 13724: }
13725:
13726: inline void msdos_int_33h_0005h()
13727: {
1.1.1.34 root 13728: // if(mouse.hidden > 0) {
13729: update_console_input();
13730: // }
1.1.1.24 root 13731: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
13732: int idx = REG16(BX);
1.1.1.34 root 13733: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff);
13734: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x));
13735: 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 13736: mouse.buttons[idx].pressed_times = 0;
13737: } else {
13738: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
13739: }
13740: REG16(AX) = mouse.get_buttons();
13741: }
13742:
13743: inline void msdos_int_33h_0006h()
13744: {
1.1.1.34 root 13745: // if(mouse.hidden > 0) {
13746: update_console_input();
13747: // }
1.1.1.24 root 13748: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
13749: int idx = REG16(BX);
1.1.1.34 root 13750: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff);
13751: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x));
13752: 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 13753: mouse.buttons[idx].released_times = 0;
13754: } else {
13755: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
13756: }
13757: REG16(AX) = mouse.get_buttons();
13758: }
13759:
13760: inline void msdos_int_33h_0007h()
13761: {
13762: mouse.min_position.x = min(REG16(CX), REG16(DX));
13763: mouse.max_position.x = max(REG16(CX), REG16(DX));
13764: }
13765:
13766: inline void msdos_int_33h_0008h()
13767: {
13768: mouse.min_position.y = min(REG16(CX), REG16(DX));
13769: mouse.max_position.y = max(REG16(CX), REG16(DX));
13770: }
13771:
13772: inline void msdos_int_33h_0009h()
13773: {
13774: mouse.hot_spot[0] = REG16(BX);
13775: mouse.hot_spot[1] = REG16(CX);
13776: }
13777:
13778: inline void msdos_int_33h_000bh()
13779: {
1.1.1.34 root 13780: // if(mouse.hidden > 0) {
13781: update_console_input();
13782: // }
1.1.1.24 root 13783: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
13784: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
13785: mouse.prev_position.x = mouse.position.x;
13786: mouse.prev_position.y = mouse.position.y;
13787: REG16(CX) = dx;
13788: REG16(DX) = dy;
13789: }
13790:
13791: inline void msdos_int_33h_000ch()
13792: {
13793: mouse.call_mask = REG16(CX);
13794: mouse.call_addr.w.l = REG16(DX);
13795: mouse.call_addr.w.h = SREG(ES);
13796: }
13797:
13798: inline void msdos_int_33h_000fh()
13799: {
13800: mouse.mickey.x = REG16(CX);
13801: mouse.mickey.y = REG16(DX);
13802: }
13803:
13804: inline void msdos_int_33h_0011h()
13805: {
13806: REG16(AX) = 0xffff;
13807: REG16(BX) = MAX_MOUSE_BUTTONS;
13808: }
13809:
13810: inline void msdos_int_33h_0014h()
13811: {
13812: UINT16 old_mask = mouse.call_mask;
13813: UINT16 old_ofs = mouse.call_addr.w.l;
13814: UINT16 old_seg = mouse.call_addr.w.h;
13815:
13816: mouse.call_mask = REG16(CX);
13817: mouse.call_addr.w.l = REG16(DX);
13818: mouse.call_addr.w.h = SREG(ES);
13819:
13820: REG16(CX) = old_mask;
13821: REG16(DX) = old_ofs;
13822: SREG(ES) = old_seg;
13823: i386_load_segment_descriptor(ES);
13824: }
13825:
13826: inline void msdos_int_33h_0015h()
13827: {
13828: REG16(BX) = sizeof(mouse);
13829: }
13830:
13831: inline void msdos_int_33h_0016h()
13832: {
13833: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
13834: }
13835:
13836: inline void msdos_int_33h_0017h()
13837: {
13838: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
13839: }
13840:
1.1.1.43! root 13841: inline void msdos_int_33h_0018h()
! 13842: {
! 13843: for(int i = 0; i < 8; i++) {
! 13844: if(REG16(CX) & (1 << i)) {
! 13845: if(mouse.call_addr_alt[i].dw && !(REG16(DX) == 0 && SREG(ES) == 0)) {
! 13846: // event handler already exists
! 13847: REG16(AX) = 0xffff;
! 13848: break;
! 13849: }
! 13850: mouse.call_addr_alt[i].w.l = REG16(DX);
! 13851: mouse.call_addr_alt[i].w.h = SREG(ES);
! 13852: }
! 13853: }
! 13854: }
! 13855:
! 13856: inline void msdos_int_33h_0019h()
! 13857: {
! 13858: UINT16 call_mask = REG16(CX);
! 13859:
! 13860: REG16(CX) = 0;
! 13861:
! 13862: for(int i = 0; i < 8; i++) {
! 13863: if((call_mask & (1 << i)) && mouse.call_addr_alt[i].dw) {
! 13864: for(int j = 0; j < 8; j++) {
! 13865: if((call_mask & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
! 13866: REG16(CX) |= (1 << j);
! 13867: }
! 13868: }
! 13869: REG16(DX) = mouse.call_addr_alt[i].w.l;
! 13870: REG16(BX) = mouse.call_addr_alt[i].w.h;
! 13871: break;
! 13872: }
! 13873: }
! 13874: }
! 13875:
1.1.1.24 root 13876: inline void msdos_int_33h_001ah()
13877: {
13878: mouse.sensitivity[0] = REG16(BX);
13879: mouse.sensitivity[1] = REG16(CX);
13880: mouse.sensitivity[2] = REG16(DX);
13881: }
13882:
13883: inline void msdos_int_33h_001bh()
13884: {
13885: REG16(BX) = mouse.sensitivity[0];
13886: REG16(CX) = mouse.sensitivity[1];
13887: REG16(DX) = mouse.sensitivity[2];
13888: }
13889:
13890: inline void msdos_int_33h_001dh()
13891: {
13892: mouse.display_page = REG16(BX);
13893: }
13894:
13895: inline void msdos_int_33h_001eh()
13896: {
13897: REG16(BX) = mouse.display_page;
13898: }
13899:
1.1.1.34 root 13900: inline void msdos_int_33h_001fh()
13901: {
13902: // from DOSBox
13903: REG16(BX) = 0x0000;
13904: SREG(ES) = 0x0000;
13905: i386_load_segment_descriptor(ES);
13906: mouse.enabled = false;
13907: mouse.old_hidden = mouse.hidden;
13908: mouse.hidden = 1;
13909: }
13910:
13911: inline void msdos_int_33h_0020h()
13912: {
13913: // from DOSBox
13914: mouse.enabled = true;
13915: mouse.hidden = mouse.old_hidden;
13916: }
13917:
1.1.1.24 root 13918: inline void msdos_int_33h_0021h()
13919: {
13920: REG16(AX) = 0xffff;
13921: REG16(BX) = MAX_MOUSE_BUTTONS;
13922: }
13923:
13924: inline void msdos_int_33h_0022h()
13925: {
13926: mouse.language = REG16(BX);
13927: }
13928:
13929: inline void msdos_int_33h_0023h()
13930: {
13931: REG16(BX) = mouse.language;
13932: }
13933:
13934: inline void msdos_int_33h_0024h()
13935: {
13936: REG16(BX) = 0x0805; // V8.05
13937: REG16(CX) = 0x0400; // PS/2
13938: }
13939:
13940: inline void msdos_int_33h_0026h()
13941: {
13942: REG16(BX) = 0x0000;
13943: REG16(CX) = mouse.max_position.x;
13944: REG16(DX) = mouse.max_position.y;
13945: }
13946:
13947: inline void msdos_int_33h_002ah()
13948: {
1.1.1.34 root 13949: REG16(AX) = -mouse.hidden;
1.1.1.24 root 13950: REG16(BX) = mouse.hot_spot[0];
13951: REG16(CX) = mouse.hot_spot[1];
13952: REG16(DX) = 4; // PS/2
13953: }
13954:
13955: inline void msdos_int_33h_0031h()
13956: {
13957: REG16(AX) = mouse.min_position.x;
13958: REG16(BX) = mouse.min_position.y;
13959: REG16(CX) = mouse.max_position.x;
13960: REG16(DX) = mouse.max_position.y;
13961: }
13962:
13963: inline void msdos_int_33h_0032h()
13964: {
13965: REG16(AX) = 0;
13966: // REG16(AX) |= 0x8000; // 0025h
13967: REG16(AX) |= 0x4000; // 0026h
13968: // REG16(AX) |= 0x2000; // 0027h
13969: // REG16(AX) |= 0x1000; // 0028h
13970: // REG16(AX) |= 0x0800; // 0029h
13971: REG16(AX) |= 0x0400; // 002ah
13972: // REG16(AX) |= 0x0200; // 002bh
13973: // REG16(AX) |= 0x0100; // 002ch
13974: // REG16(AX) |= 0x0080; // 002dh
13975: // REG16(AX) |= 0x0040; // 002eh
13976: REG16(AX) |= 0x0020; // 002fh
13977: // REG16(AX) |= 0x0010; // 0030h
13978: REG16(AX) |= 0x0008; // 0031h
13979: REG16(AX) |= 0x0004; // 0032h
13980: // REG16(AX) |= 0x0002; // 0033h
13981: // REG16(AX) |= 0x0001; // 0034h
13982: }
13983:
1.1.1.19 root 13984: inline void msdos_int_67h_40h()
13985: {
13986: if(!support_ems) {
13987: REG8(AH) = 0x84;
13988: } else {
13989: REG8(AH) = 0x00;
13990: }
13991: }
13992:
13993: inline void msdos_int_67h_41h()
13994: {
13995: if(!support_ems) {
13996: REG8(AH) = 0x84;
13997: } else {
13998: REG8(AH) = 0x00;
13999: REG16(BX) = EMS_TOP >> 4;
14000: }
14001: }
14002:
14003: inline void msdos_int_67h_42h()
14004: {
14005: if(!support_ems) {
14006: REG8(AH) = 0x84;
14007: } else {
14008: REG8(AH) = 0x00;
14009: REG16(BX) = free_ems_pages;
14010: REG16(DX) = MAX_EMS_PAGES;
14011: }
14012: }
14013:
14014: inline void msdos_int_67h_43h()
14015: {
14016: if(!support_ems) {
14017: REG8(AH) = 0x84;
14018: } else if(REG16(BX) > MAX_EMS_PAGES) {
14019: REG8(AH) = 0x87;
14020: } else if(REG16(BX) > free_ems_pages) {
14021: REG8(AH) = 0x88;
14022: } else if(REG16(BX) == 0) {
14023: REG8(AH) = 0x89;
14024: } else {
1.1.1.31 root 14025: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14026: if(!ems_handles[i].allocated) {
14027: ems_allocate_pages(i, REG16(BX));
14028: REG8(AH) = 0x00;
14029: REG16(DX) = i;
14030: return;
14031: }
14032: }
14033: REG8(AH) = 0x85;
14034: }
14035: }
14036:
14037: inline void msdos_int_67h_44h()
14038: {
14039: if(!support_ems) {
14040: REG8(AH) = 0x84;
1.1.1.31 root 14041: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14042: REG8(AH) = 0x83;
14043: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
14044: REG8(AH) = 0x8a;
14045: // } else if(!(REG8(AL) < 4)) {
14046: // REG8(AH) = 0x8b;
14047: } else if(REG16(BX) == 0xffff) {
14048: ems_unmap_page(REG8(AL) & 3);
14049: REG8(AH) = 0x00;
14050: } else {
14051: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
14052: REG8(AH) = 0x00;
14053: }
14054: }
14055:
14056: inline void msdos_int_67h_45h()
14057: {
14058: if(!support_ems) {
14059: REG8(AH) = 0x84;
1.1.1.31 root 14060: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14061: REG8(AH) = 0x83;
14062: } else {
14063: ems_release_pages(REG16(DX));
14064: REG8(AH) = 0x00;
14065: }
14066: }
14067:
14068: inline void msdos_int_67h_46h()
14069: {
14070: if(!support_ems) {
14071: REG8(AH) = 0x84;
14072: } else {
1.1.1.29 root 14073: // REG16(AX) = 0x0032; // EMS 3.2
14074: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 14075: }
14076: }
14077:
14078: inline void msdos_int_67h_47h()
14079: {
14080: // NOTE: the map data should be stored in the specified ems page, not process data
14081: process_t *process = msdos_process_info_get(current_psp);
14082:
14083: if(!support_ems) {
14084: REG8(AH) = 0x84;
1.1.1.31 root 14085: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14086: // REG8(AH) = 0x83;
14087: } else if(process->ems_pages_stored) {
14088: REG8(AH) = 0x8d;
14089: } else {
14090: for(int i = 0; i < 4; i++) {
14091: process->ems_pages[i].handle = ems_pages[i].handle;
14092: process->ems_pages[i].page = ems_pages[i].page;
14093: process->ems_pages[i].mapped = ems_pages[i].mapped;
14094: }
14095: process->ems_pages_stored = true;
14096: REG8(AH) = 0x00;
14097: }
14098: }
14099:
14100: inline void msdos_int_67h_48h()
14101: {
14102: // NOTE: the map data should be restored from the specified ems page, not process data
14103: process_t *process = msdos_process_info_get(current_psp);
14104:
14105: if(!support_ems) {
14106: REG8(AH) = 0x84;
1.1.1.31 root 14107: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14108: // REG8(AH) = 0x83;
14109: } else if(!process->ems_pages_stored) {
14110: REG8(AH) = 0x8e;
14111: } else {
14112: for(int i = 0; i < 4; i++) {
14113: if(process->ems_pages[i].mapped) {
14114: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
14115: } else {
14116: ems_unmap_page(i);
14117: }
14118: }
14119: process->ems_pages_stored = false;
14120: REG8(AH) = 0x00;
14121: }
14122: }
14123:
14124: inline void msdos_int_67h_4bh()
14125: {
14126: if(!support_ems) {
14127: REG8(AH) = 0x84;
14128: } else {
14129: REG8(AH) = 0x00;
14130: REG16(BX) = 0;
1.1.1.31 root 14131: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14132: if(ems_handles[i].allocated) {
14133: REG16(BX)++;
14134: }
14135: }
14136: }
14137: }
14138:
14139: inline void msdos_int_67h_4ch()
14140: {
14141: if(!support_ems) {
14142: REG8(AH) = 0x84;
1.1.1.31 root 14143: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14144: REG8(AH) = 0x83;
14145: } else {
14146: REG8(AH) = 0x00;
14147: REG16(BX) = ems_handles[REG16(DX)].pages;
14148: }
14149: }
14150:
14151: inline void msdos_int_67h_4dh()
14152: {
14153: if(!support_ems) {
14154: REG8(AH) = 0x84;
14155: } else {
14156: REG8(AH) = 0x00;
14157: REG16(BX) = 0;
1.1.1.31 root 14158: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14159: if(ems_handles[i].allocated) {
14160: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
14161: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
14162: REG16(BX)++;
14163: }
14164: }
14165: }
14166: }
14167:
1.1.1.20 root 14168: inline void msdos_int_67h_4eh()
14169: {
14170: if(!support_ems) {
14171: REG8(AH) = 0x84;
14172: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
14173: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
14174: // save page map
14175: for(int i = 0; i < 4; i++) {
14176: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
14177: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
14178: }
14179: }
14180: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
14181: // restore page map
14182: for(int i = 0; i < 4; i++) {
14183: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
14184: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
14185:
1.1.1.31 root 14186: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 14187: ems_map_page(i, handle, page);
14188: } else {
14189: ems_unmap_page(i);
14190: }
14191: }
14192: }
14193: REG8(AH) = 0x00;
14194: } else if(REG8(AL) == 0x03) {
14195: REG8(AH) = 0x00;
1.1.1.21 root 14196: REG8(AL) = 4 * 4;
14197: } else {
1.1.1.22 root 14198: 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 14199: REG8(AH) = 0x8f;
14200: }
14201: }
14202:
14203: inline void msdos_int_67h_4fh()
14204: {
14205: if(!support_ems) {
14206: REG8(AH) = 0x84;
14207: } else if(REG8(AL) == 0x00) {
14208: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
14209:
14210: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
14211: for(int i = 0; i < count; i++) {
14212: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
14213: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
14214:
14215: // if(!(physical < 4)) {
14216: // REG8(AH) = 0x8b;
14217: // return;
14218: // }
14219: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
1.1.1.41 root 14220: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].handle : 0xffff;
14221: *(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 14222: }
14223: REG8(AH) = 0x00;
14224: } else if(REG8(AL) == 0x01) {
14225: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
14226:
14227: for(int i = 0; i < count; i++) {
14228: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
14229: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
14230: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
14231: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
14232:
14233: // if(!(physical < 4)) {
14234: // REG8(AH) = 0x8b;
14235: // return;
14236: // } else
1.1.1.41 root 14237: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && logical < ems_handles[handle].pages) {
1.1.1.21 root 14238: ems_map_page(physical & 3, handle, logical);
14239: } else {
1.1.1.41 root 14240: ems_unmap_page(physical & 3);
1.1.1.21 root 14241: }
14242: }
14243: REG8(AH) = 0x00;
14244: } else if(REG8(AL) == 0x02) {
14245: REG8(AH) = 0x00;
14246: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 14247: } else {
1.1.1.22 root 14248: 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 14249: REG8(AH) = 0x8f;
14250: }
14251: }
14252:
14253: inline void msdos_int_67h_50h()
14254: {
14255: if(!support_ems) {
14256: REG8(AH) = 0x84;
1.1.1.31 root 14257: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 14258: REG8(AH) = 0x83;
14259: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
14260: for(int i = 0; i < REG16(CX); i++) {
14261: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
14262: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
14263:
14264: if(REG8(AL) == 0x01) {
14265: physical = ((physical << 4) - EMS_TOP) / 0x4000;
14266: }
14267: // if(!(physical < 4)) {
14268: // REG8(AH) = 0x8b;
14269: // return;
14270: // } else
14271: if(logical == 0xffff) {
14272: ems_unmap_page(physical & 3);
14273: } else if(logical < ems_handles[REG16(DX)].pages) {
14274: ems_map_page(physical & 3, REG16(DX), logical);
14275: } else {
14276: REG8(AH) = 0x8a;
14277: return;
14278: }
14279: }
14280: REG8(AH) = 0x00;
14281: } else {
1.1.1.22 root 14282: 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 14283: REG8(AH) = 0x8f;
14284: }
14285: }
14286:
1.1.1.19 root 14287: inline void msdos_int_67h_51h()
14288: {
14289: if(!support_ems) {
14290: REG8(AH) = 0x84;
1.1.1.31 root 14291: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14292: REG8(AH) = 0x83;
14293: } else if(REG16(BX) > MAX_EMS_PAGES) {
14294: REG8(AH) = 0x87;
14295: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
14296: REG8(AH) = 0x88;
14297: } else {
14298: ems_reallocate_pages(REG16(DX), REG16(BX));
14299: REG8(AH) = 0x00;
14300: }
14301: }
14302:
1.1.1.20 root 14303: inline void msdos_int_67h_52h()
14304: {
14305: if(!support_ems) {
14306: REG8(AH) = 0x84;
1.1.1.31 root 14307: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
14308: // REG8(AH) = 0x83;
1.1.1.20 root 14309: } else if(REG8(AL) == 0x00) {
14310: REG8(AL) = 0x00; // handle is volatile
14311: REG8(AH) = 0x00;
14312: } else if(REG8(AL) == 0x01) {
14313: if(REG8(BL) == 0x00) {
14314: REG8(AH) = 0x00;
14315: } else {
14316: REG8(AH) = 0x90; // undefined attribute type
14317: }
14318: } else if(REG8(AL) == 0x02) {
14319: REG8(AL) = 0x00; // only volatile handles supported
14320: REG8(AH) = 0x00;
14321: } else {
1.1.1.22 root 14322: 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 14323: REG8(AH) = 0x8f;
14324: }
14325: }
14326:
1.1.1.19 root 14327: inline void msdos_int_67h_53h()
14328: {
14329: if(!support_ems) {
14330: REG8(AH) = 0x84;
1.1.1.31 root 14331: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 14332: REG8(AH) = 0x83;
14333: } else if(REG8(AL) == 0x00) {
14334: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
14335: REG8(AH) = 0x00;
14336: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 14337: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14338: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
14339: REG8(AH) = 0xa1;
14340: return;
14341: }
14342: }
14343: REG8(AH) = 0x00;
14344: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
14345: } else {
1.1.1.22 root 14346: 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 14347: REG8(AH) = 0x8f;
1.1.1.19 root 14348: }
14349: }
14350:
14351: inline void msdos_int_67h_54h()
14352: {
14353: if(!support_ems) {
14354: REG8(AH) = 0x84;
14355: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 14356: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14357: if(ems_handles[i].allocated) {
14358: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
14359: } else {
14360: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
14361: }
14362: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
14363: }
14364: REG8(AH) = 0x00;
14365: REG8(AL) = MAX_EMS_HANDLES;
14366: } else if(REG8(AL) == 0x01) {
14367: REG8(AH) = 0xa0; // not found
1.1.1.31 root 14368: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 14369: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
14370: REG8(AH) = 0x00;
14371: REG16(DX) = i;
14372: break;
14373: }
14374: }
14375: } else if(REG8(AL) == 0x02) {
14376: REG8(AH) = 0x00;
14377: REG16(BX) = MAX_EMS_HANDLES;
14378: } else {
1.1.1.22 root 14379: 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 14380: REG8(AH) = 0x8f;
14381: }
14382: }
14383:
14384: inline void msdos_int_67h_57h_tmp()
14385: {
14386: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
14387: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
14388: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
14389: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
14390: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
14391: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
14392: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
14393: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
14394: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
14395:
1.1.1.32 root 14396: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 14397: UINT32 src_addr, dest_addr;
14398: UINT32 src_addr_max, dest_addr_max;
14399:
14400: if(src_type == 0) {
14401: src_buffer = mem;
14402: src_addr = (src_seg << 4) + src_ofs;
14403: src_addr_max = MAX_MEM;
14404: } else {
1.1.1.31 root 14405: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 14406: REG8(AH) = 0x83;
14407: return;
14408: } else if(!(src_seg < ems_handles[src_handle].pages)) {
14409: REG8(AH) = 0x8a;
14410: return;
14411: }
1.1.1.32 root 14412: if(ems_handles[src_handle].buffer != NULL) {
14413: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
14414: }
1.1.1.20 root 14415: src_addr = src_ofs;
1.1.1.32 root 14416: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 14417: }
14418: if(dest_type == 0) {
14419: dest_buffer = mem;
14420: dest_addr = (dest_seg << 4) + dest_ofs;
14421: dest_addr_max = MAX_MEM;
14422: } else {
1.1.1.31 root 14423: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 14424: REG8(AH) = 0x83;
14425: return;
14426: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
14427: REG8(AH) = 0x8a;
14428: return;
14429: }
1.1.1.32 root 14430: if(ems_handles[dest_handle].buffer != NULL) {
14431: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
14432: }
1.1.1.20 root 14433: dest_addr = dest_ofs;
1.1.1.32 root 14434: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 14435: }
1.1.1.32 root 14436: if(src_buffer != NULL && dest_buffer != NULL) {
14437: for(int i = 0; i < copy_length; i++) {
14438: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
14439: if(REG8(AL) == 0x00) {
14440: dest_buffer[dest_addr++] = src_buffer[src_addr++];
14441: } else if(REG8(AL) == 0x01) {
14442: UINT8 tmp = dest_buffer[dest_addr];
14443: dest_buffer[dest_addr++] = src_buffer[src_addr];
14444: src_buffer[src_addr++] = tmp;
14445: }
14446: } else {
14447: REG8(AH) = 0x93;
14448: return;
1.1.1.20 root 14449: }
14450: }
1.1.1.32 root 14451: REG8(AH) = 0x00;
14452: } else {
14453: REG8(AH) = 0x80;
1.1.1.20 root 14454: }
14455: }
14456:
14457: inline void msdos_int_67h_57h()
14458: {
14459: if(!support_ems) {
14460: REG8(AH) = 0x84;
14461: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
14462: struct {
14463: UINT16 handle;
14464: UINT16 page;
14465: bool mapped;
14466: } tmp_pages[4];
14467:
14468: // unmap pages to copy memory data to ems buffer
14469: for(int i = 0; i < 4; i++) {
14470: tmp_pages[i].handle = ems_pages[i].handle;
14471: tmp_pages[i].page = ems_pages[i].page;
14472: tmp_pages[i].mapped = ems_pages[i].mapped;
14473: ems_unmap_page(i);
14474: }
14475:
14476: // run move/exchange operation
14477: msdos_int_67h_57h_tmp();
14478:
14479: // restore unmapped pages
14480: for(int i = 0; i < 4; i++) {
14481: if(tmp_pages[i].mapped) {
14482: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
14483: }
14484: }
14485: } else {
1.1.1.22 root 14486: 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 14487: REG8(AH) = 0x8f;
14488: }
14489: }
14490:
14491: inline void msdos_int_67h_58h()
14492: {
14493: if(!support_ems) {
14494: REG8(AH) = 0x84;
14495: } else if(REG8(AL) == 0x00) {
14496: for(int i = 0; i < 4; i++) {
1.1.1.30 root 14497: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
14498: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 14499: }
14500: REG8(AH) = 0x00;
14501: REG16(CX) = 4;
14502: } else if(REG8(AL) == 0x01) {
14503: REG8(AH) = 0x00;
14504: REG16(CX) = 4;
14505: } else {
1.1.1.22 root 14506: 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 14507: REG8(AH) = 0x8f;
14508: }
14509: }
14510:
1.1.1.42 root 14511: inline void msdos_int_67h_59h()
14512: {
14513: if(!support_ems) {
14514: REG8(AH) = 0x84;
14515: } else if(REG8(AL) == 0x00) {
14516: REG8(AH) = 0xa4; // access denied by operating system
14517: } else if(REG8(AL) == 0x01) {
14518: REG8(AH) = 0x00;
14519: REG16(BX) = free_ems_pages;
14520: REG16(DX) = MAX_EMS_PAGES;
14521: } else {
14522: 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));
14523: REG8(AH) = 0x8f;
14524: }
14525: }
14526:
1.1.1.20 root 14527: inline void msdos_int_67h_5ah()
14528: {
14529: if(!support_ems) {
1.1.1.19 root 14530: REG8(AH) = 0x84;
1.1.1.20 root 14531: } else if(REG16(BX) > MAX_EMS_PAGES) {
14532: REG8(AH) = 0x87;
14533: } else if(REG16(BX) > free_ems_pages) {
14534: REG8(AH) = 0x88;
14535: // } else if(REG16(BX) == 0) {
14536: // REG8(AH) = 0x89;
14537: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 14538: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 14539: if(!ems_handles[i].allocated) {
14540: ems_allocate_pages(i, REG16(BX));
14541: REG8(AH) = 0x00;
14542: REG16(DX) = i;
14543: return;
14544: }
14545: }
14546: REG8(AH) = 0x85;
14547: } else {
1.1.1.22 root 14548: 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 14549: REG8(AH) = 0x8f;
1.1.1.19 root 14550: }
14551: }
14552:
1.1.1.43! root 14553: inline void msdos_int_67h_5dh()
! 14554: {
! 14555: if(!support_ems) {
! 14556: REG8(AH) = 0x84;
! 14557: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
! 14558: REG8(AH) = 0xa4; // operating system denied access
! 14559: } else {
! 14560: 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));
! 14561: REG8(AH) = 0x8f;
! 14562: }
! 14563: }
! 14564:
1.1.1.30 root 14565: inline void msdos_int_67h_deh()
14566: {
14567: REG8(AH) = 0x84;
14568: }
14569:
1.1.1.19 root 14570: #ifdef SUPPORT_XMS
14571:
1.1.1.32 root 14572: void msdos_xms_init()
1.1.1.26 root 14573: {
1.1.1.30 root 14574: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
14575: emb_handle_top->address = EMB_TOP;
14576: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 14577: xms_a20_local_enb_count = 0;
14578: }
14579:
1.1.1.32 root 14580: void msdos_xms_finish()
14581: {
14582: msdos_xms_release();
14583: }
14584:
14585: void msdos_xms_release()
1.1.1.30 root 14586: {
14587: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
14588: emb_handle_t *next_handle = emb_handle->next;
14589: free(emb_handle);
14590: emb_handle = next_handle;
14591: }
14592: }
14593:
14594: emb_handle_t *msdos_xms_get_emb_handle(int handle)
14595: {
14596: if(handle != 0) {
14597: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
14598: if(emb_handle->handle == handle) {
14599: return(emb_handle);
14600: }
14601: }
14602: }
14603: return(NULL);
14604: }
14605:
14606: int msdos_xms_get_unused_emb_handle_id()
14607: {
14608: for(int handle = 1;; handle++) {
14609: if(msdos_xms_get_emb_handle(handle) == NULL) {
14610: return(handle);
14611: }
14612: }
14613: return(0);
14614: }
14615:
14616: int msdos_xms_get_unused_emb_handle_count()
14617: {
14618: int count = 64; //255;
14619:
14620: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
14621: if(emb_handle->handle != 0) {
14622: if(--count == 1) {
14623: break;
14624: }
14625: }
14626: }
14627: return(count);
14628: }
14629:
14630: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
14631: {
14632: if(emb_handle->size_kb > size_kb) {
14633: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
14634:
14635: new_handle->address = emb_handle->address + size_kb * 1024;
14636: new_handle->size_kb = emb_handle->size_kb - size_kb;
14637: emb_handle->size_kb = size_kb;
14638:
14639: new_handle->prev = emb_handle;
14640: new_handle->next = emb_handle->next;
14641: if(emb_handle->next != NULL) {
14642: emb_handle->next->prev = new_handle;
14643: }
14644: emb_handle->next = new_handle;
14645: }
14646: }
14647:
14648: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
14649: {
14650: emb_handle_t *next_handle = emb_handle->next;
14651:
14652: if(next_handle != NULL) {
14653: emb_handle->size_kb += next_handle->size_kb;
14654:
14655: if(next_handle->next != NULL) {
14656: next_handle->next->prev = emb_handle;
14657: }
14658: emb_handle->next = next_handle->next;
14659: free(next_handle);
14660: }
14661: }
14662:
14663: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
14664: {
14665: emb_handle_t *target_handle = NULL;
14666:
14667: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
14668: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
14669: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
14670: target_handle = emb_handle;
14671: }
14672: }
14673: }
14674: if(target_handle != NULL) {
14675: if(target_handle->size_kb > size_kb) {
14676: msdos_xms_split_emb_handle(target_handle, size_kb);
14677: }
14678: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
14679: return(target_handle);
14680: }
14681: return(NULL);
14682: }
14683:
14684: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
14685: {
14686: emb_handle_t *prev_handle = emb_handle->prev;
14687: emb_handle_t *next_handle = emb_handle->next;
14688:
14689: if(prev_handle != NULL && prev_handle->handle == 0) {
14690: msdos_xms_combine_emb_handles(prev_handle);
14691: emb_handle = prev_handle;
14692: }
14693: if(next_handle != NULL && next_handle->handle == 0) {
14694: msdos_xms_combine_emb_handles(emb_handle);
14695: }
14696: emb_handle->handle = 0;
14697: }
14698:
1.1.1.19 root 14699: inline void msdos_call_xms_00h()
14700: {
1.1.1.29 root 14701: #if defined(HAS_I386)
14702: REG16(AX) = 0x0300; // V3.00 (XMS Version)
14703: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
14704: #else
14705: REG16(AX) = 0x0200; // V2.00 (XMS Version)
14706: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
14707: #endif
14708: // REG16(DX) = 0x0000; // HMA does not exist
14709: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 14710: }
14711:
14712: inline void msdos_call_xms_01h()
14713: {
1.1.1.29 root 14714: if(REG8(AL) == 0x40) {
14715: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
14716: // DX=KB free extended memory returned by last call of function 08h
14717: REG16(AX) = 0x0000;
14718: REG8(BL) = 0x91;
14719: REG16(DX) = xms_dx_after_call_08h;
14720: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
14721: REG16(AX) = 0x0000;
14722: REG8(BL) = 0x81; // Vdisk was detected
14723: #ifdef SUPPORT_HMA
14724: } else if(is_hma_used_by_int_2fh) {
14725: REG16(AX) = 0x0000;
14726: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
14727: } else if(is_hma_used_by_xms) {
14728: REG16(AX) = 0x0000;
14729: REG8(BL) = 0x91; // HMA is already in use
14730: } else {
14731: REG16(AX) = 0x0001;
14732: is_hma_used_by_xms = true;
14733: #else
14734: } else {
14735: REG16(AX) = 0x0000;
14736: REG8(BL) = 0x91; // HMA is already in use
14737: #endif
14738: }
1.1.1.19 root 14739: }
14740:
14741: inline void msdos_call_xms_02h()
14742: {
1.1.1.29 root 14743: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
14744: REG16(AX) = 0x0000;
14745: REG8(BL) = 0x81; // Vdisk was detected
14746: #ifdef SUPPORT_HMA
14747: } else if(is_hma_used_by_int_2fh) {
14748: REG16(AX) = 0x0000;
14749: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
14750: } else if(!is_hma_used_by_xms) {
14751: REG16(AX) = 0x0000;
14752: REG8(BL) = 0x93; // HMA is not allocated
14753: } else {
14754: REG16(AX) = 0x0001;
14755: is_hma_used_by_xms = false;
14756: // restore first free mcb in high memory area
14757: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14758: #else
14759: } else {
14760: REG16(AX) = 0x0000;
14761: REG8(BL) = 0x91; // HMA is already in use
14762: #endif
14763: }
1.1.1.19 root 14764: }
14765:
14766: inline void msdos_call_xms_03h()
14767: {
14768: i386_set_a20_line(1);
14769: REG16(AX) = 0x0001;
14770: REG8(BL) = 0x00;
14771: }
14772:
14773: inline void msdos_call_xms_04h()
14774: {
1.1.1.21 root 14775: i386_set_a20_line(0);
14776: REG16(AX) = 0x0001;
14777: REG8(BL) = 0x00;
1.1.1.19 root 14778: }
14779:
14780: inline void msdos_call_xms_05h()
14781: {
14782: i386_set_a20_line(1);
14783: REG16(AX) = 0x0001;
14784: REG8(BL) = 0x00;
1.1.1.21 root 14785: xms_a20_local_enb_count++;
1.1.1.19 root 14786: }
14787:
14788: void msdos_call_xms_06h()
14789: {
1.1.1.21 root 14790: if(xms_a20_local_enb_count > 0) {
14791: xms_a20_local_enb_count--;
14792: }
14793: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 14794: i386_set_a20_line(0);
1.1.1.21 root 14795: }
14796: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 14797: REG16(AX) = 0x0000;
14798: REG8(BL) = 0x94;
1.1.1.21 root 14799: } else {
14800: REG16(AX) = 0x0001;
14801: REG8(BL) = 0x00;
1.1.1.19 root 14802: }
14803: }
14804:
14805: inline void msdos_call_xms_07h()
14806: {
14807: REG16(AX) = (m_a20_mask >> 20) & 1;
14808: REG8(BL) = 0x00;
14809: }
14810:
14811: inline void msdos_call_xms_08h()
14812: {
14813: REG16(AX) = REG16(DX) = 0x0000;
14814:
1.1.1.30 root 14815: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
14816: if(emb_handle->handle == 0) {
14817: if(REG16(AX) < emb_handle->size_kb) {
14818: REG16(AX) = emb_handle->size_kb;
1.1.1.19 root 14819: }
1.1.1.30 root 14820: REG16(DX) += emb_handle->size_kb;
1.1.1.19 root 14821: }
14822: }
14823:
14824: if(REG16(AX) == 0 && REG16(DX) == 0) {
14825: REG8(BL) = 0xa0;
14826: } else {
14827: REG8(BL) = 0x00;
14828: }
1.1.1.29 root 14829: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 14830: }
14831:
1.1.1.30 root 14832: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 14833: {
1.1.1.30 root 14834: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
14835:
14836: if(emb_handle != NULL) {
14837: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
14838:
14839: REG16(AX) = 0x0001;
14840: REG16(DX) = emb_handle->handle;
14841: REG8(BL) = 0x00;
14842: } else {
14843: REG16(AX) = REG16(DX) = 0x0000;
14844: REG8(BL) = 0xa0;
1.1.1.19 root 14845: }
1.1.1.30 root 14846: }
14847:
14848: inline void msdos_call_xms_09h()
14849: {
14850: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 14851: }
14852:
14853: inline void msdos_call_xms_0ah()
14854: {
1.1.1.30 root 14855: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14856:
14857: if(emb_handle == NULL) {
1.1.1.19 root 14858: REG16(AX) = 0x0000;
14859: REG8(BL) = 0xa2;
1.1.1.30 root 14860: } else if(emb_handle->lock > 0) {
1.1.1.19 root 14861: REG16(AX) = 0x0000;
14862: REG8(BL) = 0xab;
14863: } else {
1.1.1.30 root 14864: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 14865:
14866: REG16(AX) = 0x0001;
14867: REG8(BL) = 0x00;
14868: }
14869: }
14870:
14871: inline void msdos_call_xms_0bh()
14872: {
14873: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
14874: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
14875: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
14876: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
14877: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
14878:
14879: UINT8 *src_buffer, *dest_buffer;
14880: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 14881: emb_handle_t *emb_handle;
1.1.1.19 root 14882:
14883: if(src_handle == 0) {
14884: src_buffer = mem;
14885: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
14886: src_addr_max = MAX_MEM;
1.1.1.30 root 14887:
1.1.1.19 root 14888: } else {
1.1.1.30 root 14889: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 14890: REG16(AX) = 0x0000;
14891: REG8(BL) = 0xa3;
14892: return;
14893: }
1.1.1.30 root 14894: src_buffer = mem + emb_handle->address;
14895: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 14896: }
14897: if(dest_handle == 0) {
14898: dest_buffer = mem;
14899: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
14900: dest_addr_max = MAX_MEM;
14901: } else {
1.1.1.30 root 14902: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 14903: REG16(AX) = 0x0000;
14904: REG8(BL) = 0xa5;
14905: return;
14906: }
1.1.1.30 root 14907: dest_buffer = mem + emb_handle->address;
14908: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 14909: }
14910: for(int i = 0; i < copy_length; i++) {
14911: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
14912: dest_buffer[dest_addr++] = src_buffer[src_addr++];
14913: } else {
14914: break;
14915: }
14916: }
14917: REG16(AX) = 0x0001;
14918: REG8(BL) = 0x00;
14919: }
14920:
14921: inline void msdos_call_xms_0ch()
14922: {
1.1.1.30 root 14923: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14924:
14925: if(emb_handle == NULL) {
1.1.1.19 root 14926: REG16(AX) = 0x0000;
14927: REG8(BL) = 0xa2;
14928: } else {
1.1.1.30 root 14929: emb_handle->lock++;
1.1.1.19 root 14930: REG16(AX) = 0x0001;
14931: REG8(BL) = 0x00;
1.1.1.30 root 14932: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
14933: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 14934: }
14935: }
14936:
14937: inline void msdos_call_xms_0dh()
14938: {
1.1.1.30 root 14939: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14940:
14941: if(emb_handle == NULL) {
1.1.1.19 root 14942: REG16(AX) = 0x0000;
14943: REG8(BL) = 0xa2;
1.1.1.30 root 14944: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 14945: REG16(AX) = 0x0000;
14946: REG8(BL) = 0xaa;
14947: } else {
1.1.1.30 root 14948: emb_handle->lock--;
1.1.1.19 root 14949: REG16(AX) = 0x0001;
14950: REG8(BL) = 0x00;
14951: }
14952: }
14953:
14954: inline void msdos_call_xms_0eh()
14955: {
1.1.1.30 root 14956: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14957:
14958: if(emb_handle == NULL) {
1.1.1.19 root 14959: REG16(AX) = 0x0000;
14960: REG8(BL) = 0xa2;
14961: } else {
14962: REG16(AX) = 0x0001;
1.1.1.30 root 14963: REG8(BH) = emb_handle->lock;
14964: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
14965: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 14966: }
14967: }
14968:
1.1.1.30 root 14969: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 14970: {
1.1.1.30 root 14971: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14972:
14973: if(emb_handle == NULL) {
1.1.1.19 root 14974: REG16(AX) = 0x0000;
14975: REG8(BL) = 0xa2;
1.1.1.30 root 14976: } else if(emb_handle->lock > 0) {
1.1.1.19 root 14977: REG16(AX) = 0x0000;
14978: REG8(BL) = 0xab;
14979: } else {
1.1.1.30 root 14980: if(emb_handle->size_kb < size_kb) {
14981: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
14982: msdos_xms_combine_emb_handles(emb_handle);
14983: if(emb_handle->size_kb > size_kb) {
14984: msdos_xms_split_emb_handle(emb_handle, size_kb);
14985: }
14986: } else {
14987: int old_handle = emb_handle->handle;
14988: int old_size_kb = emb_handle->size_kb;
14989: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
14990:
14991: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
14992: msdos_xms_free_emb_handle(emb_handle);
14993:
14994: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
14995: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
14996: }
14997: emb_handle->handle = old_handle;
14998: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
14999: free(buffer);
15000: }
15001: } else if(emb_handle->size_kb > size_kb) {
15002: msdos_xms_split_emb_handle(emb_handle, size_kb);
15003: }
15004: if(emb_handle->size_kb != size_kb) {
15005: REG16(AX) = 0x0000;
15006: REG8(BL) = 0xa0;
15007: } else {
15008: REG16(AX) = 0x0001;
15009: REG8(BL) = 0x00;
15010: }
1.1.1.19 root 15011: }
15012: }
15013:
1.1.1.30 root 15014: inline void msdos_call_xms_0fh()
15015: {
15016: msdos_call_xms_0fh(REG16(BX));
15017: }
15018:
1.1.1.19 root 15019: inline void msdos_call_xms_10h()
15020: {
15021: int seg;
15022:
15023: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
15024: REG16(AX) = 0x0001;
15025: REG16(BX) = seg;
15026: } else {
15027: REG16(AX) = 0x0000;
15028: REG8(BL) = 0xb0;
15029: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
15030: }
15031: }
15032:
15033: inline void msdos_call_xms_11h()
15034: {
15035: int mcb_seg = REG16(DX) - 1;
15036: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
15037:
15038: if(mcb->mz == 'M' || mcb->mz == 'Z') {
15039: msdos_mem_free(REG16(DX));
15040: REG16(AX) = 0x0001;
15041: REG8(BL) = 0x00;
15042: } else {
15043: REG16(AX) = 0x0000;
15044: REG8(BL) = 0xb2;
15045: }
15046: }
15047:
15048: inline void msdos_call_xms_12h()
15049: {
15050: int mcb_seg = REG16(DX) - 1;
15051: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
15052: int max_paragraphs;
15053:
15054: if(mcb->mz == 'M' || mcb->mz == 'Z') {
15055: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
15056: REG16(AX) = 0x0001;
15057: REG8(BL) = 0x00;
15058: } else {
15059: REG16(AX) = 0x0000;
15060: REG8(BL) = 0xb0;
15061: REG16(DX) = max_paragraphs;
15062: }
15063: } else {
15064: REG16(AX) = 0x0000;
15065: REG8(BL) = 0xb2;
15066: }
15067: }
15068:
1.1.1.29 root 15069: #if defined(HAS_I386)
15070:
15071: inline void msdos_call_xms_88h()
15072: {
15073: REG32(EAX) = REG32(EDX) = 0x0000;
15074:
1.1.1.30 root 15075: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
15076: if(emb_handle->handle == 0) {
15077: if(REG32(EAX) < emb_handle->size_kb) {
15078: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 15079: }
1.1.1.30 root 15080: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 15081: }
15082: }
15083:
15084: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
15085: REG8(BL) = 0xa0;
15086: } else {
15087: REG8(BL) = 0x00;
15088: }
15089: REG32(ECX) = EMB_END - 1;
15090: }
15091:
15092: inline void msdos_call_xms_89h()
15093: {
1.1.1.30 root 15094: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 15095: }
15096:
15097: inline void msdos_call_xms_8eh()
15098: {
1.1.1.30 root 15099: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
15100:
15101: if(emb_handle == NULL) {
1.1.1.29 root 15102: REG16(AX) = 0x0000;
15103: REG8(BL) = 0xa2;
15104: } else {
15105: REG16(AX) = 0x0001;
1.1.1.30 root 15106: REG8(BH) = emb_handle->lock;
15107: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
15108: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 15109: }
15110: }
15111:
15112: inline void msdos_call_xms_8fh()
15113: {
1.1.1.30 root 15114: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 15115: }
15116:
15117: #endif
1.1.1.19 root 15118: #endif
15119:
1.1.1.26 root 15120: UINT16 msdos_get_equipment()
15121: {
15122: static UINT16 equip = 0;
15123:
15124: if(equip == 0) {
15125: #ifdef SUPPORT_FPU
15126: equip |= (1 << 1); // 80x87 coprocessor installed
15127: #endif
15128: equip |= (1 << 2); // pointing device installed (PS/2)
15129: equip |= (2 << 4); // initial video mode (80x25 color)
15130: // equip |= (1 << 8); // 0 if DMA installed
15131: equip |= (2 << 9); // number of serial ports
15132: 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 15133:
15134: // check only A: and B: if it is floppy drive
15135: DWORD dwDrives = GetLogicalDrives();
15136: int n = 0;
15137: for(int i = 0; i < 2; i++) {
15138: if(dwDrives & (1 << i)) {
15139: char volume[] = "A:\\";
15140: volume[0] = 'A' + i;
15141: if(GetDriveType(volume) == DRIVE_REMOVABLE) {
15142: n++;
15143: }
15144: }
15145: }
15146: if(n != 0) {
15147: equip |= (1 << 0); // floppy disk(s) installed
15148: n--;
15149: equip |= (n << 6); // number of floppies installed less 1
15150: }
15151: // if(joyGetNumDevs() != 0) {
15152: // equip |= (1 << 12); // game port installed
15153: // }
1.1.1.26 root 15154: }
15155: return(equip);
15156: }
15157:
1.1 root 15158: void msdos_syscall(unsigned num)
15159: {
1.1.1.22 root 15160: #ifdef ENABLE_DEBUG_SYSCALL
1.1.1.43! root 15161: if(num == 0x08 || num == 0x1c) {
! 15162: // don't log the timer interrupts
! 15163: } else if(num == 0x68) {
1.1.1.22 root 15164: // dummy interrupt for EMS (int 67h)
1.1.1.33 root 15165: 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 15166: } else if(num == 0x69) {
15167: // dummy interrupt for XMS (call far)
1.1.1.33 root 15168: fprintf(fp_debug_log, "call XMS (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.22 root 15169: } else if(num == 0x6a) {
15170: // dummy interrupt for case map routine pointed in the country info
15171: } else {
1.1.1.33 root 15172: 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 15173: }
15174: #endif
1.1.1.36 root 15175: // update cursor position
15176: if(cursor_moved) {
15177: pcbios_update_cursor_position();
15178: cursor_moved = false;
15179: }
1.1.1.33 root 15180: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
1.1.1.22 root 15181:
1.1 root 15182: switch(num) {
15183: case 0x00:
1.1.1.28 root 15184: try {
15185: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
15186: error("division by zero\n");
15187: } catch(...) {
15188: fatalerror("division by zero detected, and failed to terminate current process\n");
15189: }
1.1 root 15190: break;
15191: case 0x04:
1.1.1.28 root 15192: try {
15193: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
15194: error("overflow\n");
15195: } catch(...) {
15196: fatalerror("overflow detected, and failed to terminate current process\n");
15197: }
1.1 root 15198: break;
15199: case 0x06:
15200: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 15201: if(!ignore_illegal_insn) {
1.1.1.28 root 15202: try {
15203: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
15204: error("illegal instruction\n");
15205: } catch(...) {
15206: fatalerror("illegal instruction detected, and failed to terminate current process\n");
15207: }
1.1.1.14 root 15208: } else {
15209: #if defined(HAS_I386)
1.1.1.39 root 15210: m_eip = m_int6h_skip_eip;
15211: #elif defined(HAS_I286)
15212: m_pc = m_int6h_skip_pc;
1.1.1.14 root 15213: #else
1.1.1.39 root 15214: // 8086/80186 ignore an invalid opcode
1.1.1.14 root 15215: #endif
15216: }
1.1 root 15217: break;
1.1.1.33 root 15218: case 0x09:
15219: // ctrl-break is pressed
15220: if(raise_int_1bh) {
15221: #if defined(HAS_I386)
15222: m_ext = 0; // not an external interrupt
15223: i386_trap(0x1b, 1, 0);
15224: m_ext = 1;
15225: #else
15226: PREFIX86(_interrupt)(0x1b);
15227: #endif
15228: raise_int_1bh = false;
15229: }
1.1.1.8 root 15230: case 0x08:
1.1.1.14 root 15231: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 15232: case 0x0b:
15233: case 0x0c:
15234: case 0x0d:
15235: case 0x0e:
15236: case 0x0f:
15237: // EOI
15238: pic[0].isr &= ~(1 << (num - 0x08));
15239: pic_update();
15240: break;
1.1 root 15241: case 0x10:
15242: // PC BIOS - Video
1.1.1.14 root 15243: if(!restore_console_on_exit) {
1.1.1.15 root 15244: change_console_size(scr_width, scr_height);
1.1 root 15245: }
1.1.1.3 root 15246: m_CF = 0;
1.1 root 15247: switch(REG8(AH)) {
1.1.1.16 root 15248: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 15249: case 0x01: pcbios_int_10h_01h(); break;
15250: case 0x02: pcbios_int_10h_02h(); break;
15251: case 0x03: pcbios_int_10h_03h(); break;
15252: case 0x05: pcbios_int_10h_05h(); break;
15253: case 0x06: pcbios_int_10h_06h(); break;
15254: case 0x07: pcbios_int_10h_07h(); break;
15255: case 0x08: pcbios_int_10h_08h(); break;
15256: case 0x09: pcbios_int_10h_09h(); break;
15257: case 0x0a: pcbios_int_10h_0ah(); break;
15258: case 0x0b: break;
1.1.1.40 root 15259: case 0x0c: pcbios_int_10h_0ch(); break;
15260: case 0x0d: pcbios_int_10h_0dh(); break;
1.1 root 15261: case 0x0e: pcbios_int_10h_0eh(); break;
15262: case 0x0f: pcbios_int_10h_0fh(); break;
15263: case 0x10: break;
1.1.1.14 root 15264: case 0x11: pcbios_int_10h_11h(); break;
15265: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 15266: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 15267: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 15268: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 15269: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
15270: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 15271: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 15272: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
15273: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 15274: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 15275: case 0x6f: break;
1.1.1.22 root 15276: case 0x80: m_CF = 1; break; // unknown
15277: case 0x81: m_CF = 1; break; // unknown
1.1 root 15278: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 15279: case 0x83: pcbios_int_10h_83h(); break;
15280: case 0x8b: break;
15281: case 0x8c: m_CF = 1; break; // unknown
15282: case 0x8d: m_CF = 1; break; // unknown
15283: case 0x8e: m_CF = 1; break; // unknown
15284: case 0x90: pcbios_int_10h_90h(); break;
15285: case 0x91: pcbios_int_10h_91h(); break;
15286: case 0x92: break;
15287: case 0x93: break;
15288: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 15289: case 0xfa: break; // ega register interface library is not installed
1.1 root 15290: case 0xfe: pcbios_int_10h_feh(); break;
15291: case 0xff: pcbios_int_10h_ffh(); break;
15292: default:
1.1.1.22 root 15293: 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));
15294: m_CF = 1;
1.1 root 15295: break;
15296: }
15297: break;
15298: case 0x11:
15299: // PC BIOS - Get Equipment List
1.1.1.26 root 15300: REG16(AX) = msdos_get_equipment();
1.1 root 15301: break;
15302: case 0x12:
15303: // PC BIOS - Get Memory Size
1.1.1.33 root 15304: REG16(AX) = *(UINT16 *)(mem + 0x413);
1.1 root 15305: break;
15306: case 0x13:
1.1.1.42 root 15307: // PC BIOS - Disk I/O
15308: {
15309: static UINT8 last = 0x00;
15310: switch(REG8(AH)) {
15311: case 0x00: pcbios_int_13h_00h(); break;
15312: case 0x01: // get last status
15313: REG8(AH) = last;
15314: break;
15315: case 0x02: pcbios_int_13h_02h(); break;
15316: case 0x03: pcbios_int_13h_03h(); break;
15317: case 0x04: pcbios_int_13h_04h(); break;
15318: case 0x08: pcbios_int_13h_08h(); break;
15319: case 0x0a: pcbios_int_13h_02h(); break;
15320: case 0x0b: pcbios_int_13h_03h(); break;
15321: case 0x0d: pcbios_int_13h_00h(); break;
15322: case 0x10: pcbios_int_13h_10h(); break;
15323: case 0x15: pcbios_int_13h_15h(); break;
1.1.1.43! root 15324: case 0x41: pcbios_int_13h_41h(); break;
1.1.1.42 root 15325: case 0x05: // format
15326: case 0x06:
15327: case 0x07:
15328: REG8(AH) = 0x0c; // unsupported track or invalid media
15329: m_CF = 1;
15330: break;
15331: case 0x09:
15332: case 0x0c: // seek
15333: case 0x11: // recalib
15334: case 0x14:
15335: case 0x17:
15336: REG8(AH) = 0x00; // successful completion
15337: break;
1.1.1.43! root 15338: case 0x21: // QUICKCACHE II v4.20 - Flush Cache
! 15339: case 0xa1: // Super PC-Kwik v3.20+ - Flush Cache
! 15340: REG8(AH) = 0x01; // invalid function
! 15341: m_CF = 1;
! 15342: break;
1.1.1.42 root 15343: default:
15344: 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));
15345: REG8(AH) = 0x01; // invalid function
15346: m_CF = 1;
15347: break;
15348: }
15349: last = REG8(AH);
15350: }
1.1 root 15351: break;
15352: case 0x14:
15353: // PC BIOS - Serial I/O
1.1.1.25 root 15354: switch(REG8(AH)) {
15355: case 0x00: pcbios_int_14h_00h(); break;
15356: case 0x01: pcbios_int_14h_01h(); break;
15357: case 0x02: pcbios_int_14h_02h(); break;
15358: case 0x03: pcbios_int_14h_03h(); break;
15359: case 0x04: pcbios_int_14h_04h(); break;
15360: case 0x05: pcbios_int_14h_05h(); break;
15361: default:
15362: 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));
15363: break;
15364: }
1.1 root 15365: break;
15366: case 0x15:
15367: // PC BIOS
1.1.1.3 root 15368: m_CF = 0;
1.1 root 15369: switch(REG8(AH)) {
1.1.1.14 root 15370: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 15371: case 0x23: pcbios_int_15h_23h(); break;
15372: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 15373: case 0x41: break;
1.1 root 15374: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 15375: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 15376: case 0x53: pcbios_int_15h_53h(); break;
1.1.1.43! root 15377: case 0x84: pcbios_int_15h_84h(); break;
1.1 root 15378: case 0x86: pcbios_int_15h_86h(); break;
15379: case 0x87: pcbios_int_15h_87h(); break;
15380: case 0x88: pcbios_int_15h_88h(); break;
15381: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 15382: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 15383: case 0xc0: // PS/2 ???
15384: case 0xc1:
15385: case 0xc2:
1.1.1.30 root 15386: case 0xc3: // PS50+ ???
15387: case 0xc4:
1.1.1.22 root 15388: REG8(AH) = 0x86;
15389: m_CF = 1;
15390: break;
1.1.1.3 root 15391: #if defined(HAS_I386)
1.1 root 15392: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 15393: #endif
1.1 root 15394: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 15395: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 15396: default:
1.1.1.22 root 15397: 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));
15398: REG8(AH) = 0x86;
1.1.1.3 root 15399: m_CF = 1;
1.1 root 15400: break;
15401: }
15402: break;
15403: case 0x16:
15404: // PC BIOS - Keyboard
1.1.1.3 root 15405: m_CF = 0;
1.1 root 15406: switch(REG8(AH)) {
15407: case 0x00: pcbios_int_16h_00h(); break;
15408: case 0x01: pcbios_int_16h_01h(); break;
15409: case 0x02: pcbios_int_16h_02h(); break;
15410: case 0x03: pcbios_int_16h_03h(); break;
15411: case 0x05: pcbios_int_16h_05h(); break;
15412: case 0x10: pcbios_int_16h_00h(); break;
15413: case 0x11: pcbios_int_16h_01h(); break;
15414: case 0x12: pcbios_int_16h_12h(); break;
15415: case 0x13: pcbios_int_16h_13h(); break;
15416: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 15417: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 15418: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 15419: case 0xda: break; // unknown
1.1.1.43! root 15420: case 0xdb: break; // unknown
1.1.1.22 root 15421: case 0xff: break; // unknown
1.1 root 15422: default:
1.1.1.22 root 15423: 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 15424: break;
15425: }
15426: break;
15427: case 0x17:
15428: // PC BIOS - Printer
1.1.1.37 root 15429: m_CF = 0;
15430: switch(REG8(AH)) {
15431: case 0x00: pcbios_int_17h_00h(); break;
15432: case 0x01: pcbios_int_17h_01h(); break;
15433: case 0x02: pcbios_int_17h_02h(); break;
15434: case 0x03: pcbios_int_17h_03h(); break;
15435: case 0x50: pcbios_int_17h_50h(); break;
15436: case 0x51: pcbios_int_17h_51h(); break;
15437: case 0x52: pcbios_int_17h_52h(); break;
15438: case 0x84: pcbios_int_17h_84h(); break;
15439: case 0x85: pcbios_int_17h_85h(); break;
15440: default:
15441: 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));
15442: break;
15443: }
1.1 root 15444: break;
15445: case 0x1a:
15446: // PC BIOS - Timer
1.1.1.3 root 15447: m_CF = 0;
1.1 root 15448: switch(REG8(AH)) {
15449: case 0x00: pcbios_int_1ah_00h(); break;
15450: case 0x01: break;
15451: case 0x02: pcbios_int_1ah_02h(); break;
15452: case 0x03: break;
15453: case 0x04: pcbios_int_1ah_04h(); break;
15454: case 0x05: break;
15455: case 0x0a: pcbios_int_1ah_0ah(); break;
15456: case 0x0b: break;
1.1.1.14 root 15457: case 0x35: break; // Word Perfect Third Party Interface?
15458: case 0x36: break; // Word Perfect Third Party Interface
15459: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1.1.43! root 15460: case 0xb1: break; // PCI BIOS v2.0c+
! 15461: case 0xb4: break; // Intel Plug-and-Play Auto-Configuration
1.1 root 15462: default:
1.1.1.22 root 15463: 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 15464: break;
15465: }
15466: break;
1.1.1.33 root 15467: case 0x1b:
15468: mem[0x471] = 0x00;
15469: break;
1.1 root 15470: case 0x20:
1.1.1.28 root 15471: try {
15472: msdos_process_terminate(SREG(CS), retval, 1);
15473: } catch(...) {
15474: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
15475: }
1.1 root 15476: break;
15477: case 0x21:
15478: // MS-DOS System Call
1.1.1.3 root 15479: m_CF = 0;
1.1.1.28 root 15480: try {
15481: switch(REG8(AH)) {
15482: case 0x00: msdos_int_21h_00h(); break;
15483: case 0x01: msdos_int_21h_01h(); break;
15484: case 0x02: msdos_int_21h_02h(); break;
15485: case 0x03: msdos_int_21h_03h(); break;
15486: case 0x04: msdos_int_21h_04h(); break;
15487: case 0x05: msdos_int_21h_05h(); break;
15488: case 0x06: msdos_int_21h_06h(); break;
15489: case 0x07: msdos_int_21h_07h(); break;
15490: case 0x08: msdos_int_21h_08h(); break;
15491: case 0x09: msdos_int_21h_09h(); break;
15492: case 0x0a: msdos_int_21h_0ah(); break;
15493: case 0x0b: msdos_int_21h_0bh(); break;
15494: case 0x0c: msdos_int_21h_0ch(); break;
15495: case 0x0d: msdos_int_21h_0dh(); break;
15496: case 0x0e: msdos_int_21h_0eh(); break;
15497: case 0x0f: msdos_int_21h_0fh(); break;
15498: case 0x10: msdos_int_21h_10h(); break;
15499: case 0x11: msdos_int_21h_11h(); break;
15500: case 0x12: msdos_int_21h_12h(); break;
15501: case 0x13: msdos_int_21h_13h(); break;
15502: case 0x14: msdos_int_21h_14h(); break;
15503: case 0x15: msdos_int_21h_15h(); break;
15504: case 0x16: msdos_int_21h_16h(); break;
15505: case 0x17: msdos_int_21h_17h(); break;
15506: case 0x18: msdos_int_21h_18h(); break;
15507: case 0x19: msdos_int_21h_19h(); break;
15508: case 0x1a: msdos_int_21h_1ah(); break;
15509: case 0x1b: msdos_int_21h_1bh(); break;
15510: case 0x1c: msdos_int_21h_1ch(); break;
15511: case 0x1d: msdos_int_21h_1dh(); break;
15512: case 0x1e: msdos_int_21h_1eh(); break;
15513: case 0x1f: msdos_int_21h_1fh(); break;
15514: case 0x20: msdos_int_21h_20h(); break;
15515: case 0x21: msdos_int_21h_21h(); break;
15516: case 0x22: msdos_int_21h_22h(); break;
15517: case 0x23: msdos_int_21h_23h(); break;
15518: case 0x24: msdos_int_21h_24h(); break;
15519: case 0x25: msdos_int_21h_25h(); break;
15520: case 0x26: msdos_int_21h_26h(); break;
15521: case 0x27: msdos_int_21h_27h(); break;
15522: case 0x28: msdos_int_21h_28h(); break;
15523: case 0x29: msdos_int_21h_29h(); break;
15524: case 0x2a: msdos_int_21h_2ah(); break;
15525: case 0x2b: msdos_int_21h_2bh(); break;
15526: case 0x2c: msdos_int_21h_2ch(); break;
15527: case 0x2d: msdos_int_21h_2dh(); break;
15528: case 0x2e: msdos_int_21h_2eh(); break;
15529: case 0x2f: msdos_int_21h_2fh(); break;
15530: case 0x30: msdos_int_21h_30h(); break;
15531: case 0x31: msdos_int_21h_31h(); break;
15532: case 0x32: msdos_int_21h_32h(); break;
15533: case 0x33: msdos_int_21h_33h(); break;
15534: case 0x34: msdos_int_21h_34h(); break;
15535: case 0x35: msdos_int_21h_35h(); break;
15536: case 0x36: msdos_int_21h_36h(); break;
15537: case 0x37: msdos_int_21h_37h(); break;
15538: case 0x38: msdos_int_21h_38h(); break;
15539: case 0x39: msdos_int_21h_39h(0); break;
15540: case 0x3a: msdos_int_21h_3ah(0); break;
15541: case 0x3b: msdos_int_21h_3bh(0); break;
15542: case 0x3c: msdos_int_21h_3ch(); break;
15543: case 0x3d: msdos_int_21h_3dh(); break;
15544: case 0x3e: msdos_int_21h_3eh(); break;
15545: case 0x3f: msdos_int_21h_3fh(); break;
15546: case 0x40: msdos_int_21h_40h(); break;
15547: case 0x41: msdos_int_21h_41h(0); break;
15548: case 0x42: msdos_int_21h_42h(); break;
15549: case 0x43: msdos_int_21h_43h(0); break;
15550: case 0x44: msdos_int_21h_44h(); break;
15551: case 0x45: msdos_int_21h_45h(); break;
15552: case 0x46: msdos_int_21h_46h(); break;
15553: case 0x47: msdos_int_21h_47h(0); break;
15554: case 0x48: msdos_int_21h_48h(); break;
15555: case 0x49: msdos_int_21h_49h(); break;
15556: case 0x4a: msdos_int_21h_4ah(); break;
15557: case 0x4b: msdos_int_21h_4bh(); break;
15558: case 0x4c: msdos_int_21h_4ch(); break;
15559: case 0x4d: msdos_int_21h_4dh(); break;
15560: case 0x4e: msdos_int_21h_4eh(); break;
15561: case 0x4f: msdos_int_21h_4fh(); break;
15562: case 0x50: msdos_int_21h_50h(); break;
15563: case 0x51: msdos_int_21h_51h(); break;
15564: case 0x52: msdos_int_21h_52h(); break;
1.1.1.43! root 15565: case 0x53: msdos_int_21h_53h(); break;
1.1.1.28 root 15566: case 0x54: msdos_int_21h_54h(); break;
15567: case 0x55: msdos_int_21h_55h(); break;
15568: case 0x56: msdos_int_21h_56h(0); break;
15569: case 0x57: msdos_int_21h_57h(); break;
15570: case 0x58: msdos_int_21h_58h(); break;
15571: case 0x59: msdos_int_21h_59h(); break;
15572: case 0x5a: msdos_int_21h_5ah(); break;
15573: case 0x5b: msdos_int_21h_5bh(); break;
15574: case 0x5c: msdos_int_21h_5ch(); break;
15575: case 0x5d: msdos_int_21h_5dh(); break;
1.1.1.42 root 15576: case 0x5e: msdos_int_21h_5eh(); break;
1.1.1.30 root 15577: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 15578: case 0x60: msdos_int_21h_60h(0); break;
15579: case 0x61: msdos_int_21h_61h(); break;
15580: case 0x62: msdos_int_21h_62h(); break;
15581: case 0x63: msdos_int_21h_63h(); break;
1.1.1.33 root 15582: // 0x64: Set Device Driver Lockahead Flag
1.1.1.28 root 15583: case 0x65: msdos_int_21h_65h(); break;
15584: case 0x66: msdos_int_21h_66h(); break;
15585: case 0x67: msdos_int_21h_67h(); break;
15586: case 0x68: msdos_int_21h_68h(); break;
15587: case 0x69: msdos_int_21h_69h(); break;
15588: case 0x6a: msdos_int_21h_6ah(); break;
15589: case 0x6b: msdos_int_21h_6bh(); break;
15590: case 0x6c: msdos_int_21h_6ch(0); break;
1.1.1.33 root 15591: // 0x6d: Find First ROM Program
15592: // 0x6e: Find Next ROM Program
15593: // 0x6f: Get/Set ROM Scan Start Address
1.1.1.43! root 15594: case 0x70: msdos_int_21h_70h(); break;
1.1.1.28 root 15595: case 0x71:
1.1.1.33 root 15596: // Windows95 - Long Filename Functions
1.1.1.28 root 15597: switch(REG8(AL)) {
15598: case 0x0d: msdos_int_21h_710dh(); break;
15599: case 0x39: msdos_int_21h_39h(1); break;
15600: case 0x3a: msdos_int_21h_3ah(1); break;
15601: case 0x3b: msdos_int_21h_3bh(1); break;
15602: case 0x41: msdos_int_21h_7141h(1); break;
15603: case 0x43: msdos_int_21h_43h(1); break;
15604: case 0x47: msdos_int_21h_47h(1); break;
15605: case 0x4e: msdos_int_21h_714eh(); break;
15606: case 0x4f: msdos_int_21h_714fh(); break;
15607: case 0x56: msdos_int_21h_56h(1); break;
15608: case 0x60: msdos_int_21h_60h(1); break;
15609: case 0x6c: msdos_int_21h_6ch(1); break;
15610: case 0xa0: msdos_int_21h_71a0h(); break;
15611: case 0xa1: msdos_int_21h_71a1h(); break;
15612: case 0xa6: msdos_int_21h_71a6h(); break;
15613: case 0xa7: msdos_int_21h_71a7h(); break;
15614: case 0xa8: msdos_int_21h_71a8h(); break;
1.1.1.33 root 15615: // 0xa9: Server Create/Open File
1.1.1.28 root 15616: case 0xaa: msdos_int_21h_71aah(); break;
15617: default:
15618: 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));
15619: REG16(AX) = 0x7100;
15620: m_CF = 1;
15621: break;
15622: }
15623: break;
15624: // 0x72: Windows95 beta - LFN FindClose
15625: case 0x73:
1.1.1.33 root 15626: // Windows95 - FAT32 Functions
1.1.1.28 root 15627: switch(REG8(AL)) {
15628: case 0x00: msdos_int_21h_7300h(); break;
1.1.1.33 root 15629: // 0x01: Set Drive Locking ???
1.1.1.28 root 15630: case 0x02: msdos_int_21h_7302h(); break;
15631: case 0x03: msdos_int_21h_7303h(); break;
1.1.1.33 root 15632: // 0x04: Set DPB to Use for Formatting
15633: // 0x05: Extended Absolute Disk Read/Write
1.1.1.28 root 15634: default:
15635: 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));
15636: REG16(AX) = 0x7300;
15637: m_CF = 1;
15638: break;
15639: }
1.1 root 15640: break;
1.1.1.30 root 15641: case 0xdb: msdos_int_21h_dbh(); break;
15642: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 15643: default:
1.1.1.22 root 15644: 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 15645: REG16(AX) = 0x01;
1.1.1.3 root 15646: m_CF = 1;
1.1 root 15647: break;
15648: }
1.1.1.28 root 15649: } catch(int error) {
15650: REG16(AX) = error;
15651: m_CF = 1;
15652: } catch(...) {
15653: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 15654: m_CF = 1;
1.1 root 15655: }
1.1.1.3 root 15656: if(m_CF) {
1.1.1.23 root 15657: sda_t *sda = (sda_t *)(mem + SDA_TOP);
15658: sda->extended_error_code = REG16(AX);
15659: switch(sda->extended_error_code) {
15660: case 4: // Too many open files
15661: case 8: // Insufficient memory
15662: sda->error_class = 1; // Out of resource
15663: break;
15664: case 5: // Access denied
15665: sda->error_class = 3; // Authorization
15666: break;
15667: case 7: // Memory control block destroyed
15668: sda->error_class = 4; // Internal
15669: break;
15670: case 2: // File not found
15671: case 3: // Path not found
15672: case 15: // Invaid drive specified
15673: case 18: // No more files
15674: sda->error_class = 8; // Not found
15675: break;
15676: case 32: // Sharing violation
15677: case 33: // Lock violation
15678: sda->error_class = 10; // Locked
15679: break;
15680: // case 16: // Removal of current directory attempted
15681: case 19: // Attempted write on protected disk
15682: case 21: // Drive not ready
15683: // case 29: // Write failure
15684: // case 30: // Read failure
15685: // case 82: // Cannot create subdirectory
15686: sda->error_class = 11; // Media
15687: break;
15688: case 80: // File already exists
15689: sda->error_class = 12; // Already exist
15690: break;
15691: default:
15692: sda->error_class = 13; // Unknown
15693: break;
15694: }
15695: sda->suggested_action = 1; // Retry
15696: sda->locus_of_last_error = 1; // Unknown
1.1 root 15697: }
1.1.1.33 root 15698: if(ctrl_break_checking && ctrl_break_detected) {
1.1.1.26 root 15699: // raise int 23h
15700: #if defined(HAS_I386)
15701: m_ext = 0; // not an external interrupt
15702: i386_trap(0x23, 1, 0);
15703: m_ext = 1;
15704: #else
15705: PREFIX86(_interrupt)(0x23);
15706: #endif
15707: }
1.1 root 15708: break;
15709: case 0x22:
15710: fatalerror("int 22h (terminate address)\n");
15711: case 0x23:
1.1.1.28 root 15712: try {
15713: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
15714: } catch(...) {
15715: fatalerror("failed to terminate the current process by int 23h\n");
15716: }
1.1 root 15717: break;
15718: case 0x24:
1.1.1.32 root 15719: /*
1.1.1.28 root 15720: try {
15721: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
15722: } catch(...) {
15723: fatalerror("failed to terminate the current process by int 24h\n");
15724: }
1.1.1.32 root 15725: */
15726: msdos_int_24h();
1.1 root 15727: break;
15728: case 0x25:
15729: msdos_int_25h();
15730: break;
15731: case 0x26:
15732: msdos_int_26h();
15733: break;
15734: case 0x27:
1.1.1.28 root 15735: try {
15736: msdos_int_27h();
15737: } catch(...) {
15738: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
15739: }
1.1 root 15740: break;
15741: case 0x28:
15742: Sleep(10);
1.1.1.35 root 15743: REQUEST_HARDWRE_UPDATE();
1.1 root 15744: break;
15745: case 0x29:
15746: msdos_int_29h();
15747: break;
15748: case 0x2e:
15749: msdos_int_2eh();
15750: break;
15751: case 0x2f:
15752: // multiplex interrupt
15753: switch(REG8(AH)) {
1.1.1.22 root 15754: case 0x05: msdos_int_2fh_05h(); break;
15755: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 15756: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 15757: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 15758: case 0x14: msdos_int_2fh_14h(); break;
15759: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 15760: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 15761: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 15762: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 15763: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 15764: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 15765: case 0x46: msdos_int_2fh_46h(); break;
15766: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 15767: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 15768: case 0x4b: msdos_int_2fh_4bh(); break;
1.1 root 15769: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 15770: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.24 root 15771: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 15772: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.34 root 15773: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.43! root 15774: default:
1.1.1.30 root 15775: switch(REG8(AL)) {
15776: case 0x00:
15777: // This is not installed
15778: // REG8(AL) = 0x00;
15779: break;
1.1.1.33 root 15780: case 0x01:
1.1.1.42 root 15781: // Quarterdeck RPCI - QEMM/QRAM - PCL-838.EXE is not installed
15782: if(REG8(AH) == 0xd2 && REG16(BX) == 0x5145 && REG16(CX) == 0x4d4d && REG16(DX) == 0x3432) {
15783: break;
15784: }
1.1.1.33 root 15785: // Banyan VINES v4+ is not installed
15786: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
15787: break;
15788: }
1.1.1.42 root 15789: // Quarterdeck QDPMI.SYS v1.0 is not installed
15790: if(REG8(AH) == 0xde && REG16(BX) == 0x4450 && REG16(CX) == 0x4d49 && REG16(DX) == 0x8f4f) {
15791: break;
15792: }
1.1.1.30 root 15793: default:
1.1.1.42 root 15794: // NORTON UTILITIES 5.0+
15795: if(REG8(AH) == 0xfe && REG16(DI) == 0x4e55) {
15796: break;
15797: }
1.1.1.30 root 15798: 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 15799: REG16(AX) = 0x01; // invalid function
1.1.1.30 root 15800: m_CF = 1;
15801: break;
15802: }
15803: break;
1.1 root 15804: }
15805: break;
1.1.1.24 root 15806: case 0x33:
15807: switch(REG8(AH)) {
15808: case 0x00:
15809: // Mouse
15810: switch(REG8(AL)) {
15811: case 0x00: msdos_int_33h_0000h(); break;
15812: case 0x01: msdos_int_33h_0001h(); break;
15813: case 0x02: msdos_int_33h_0002h(); break;
15814: case 0x03: msdos_int_33h_0003h(); break;
1.1.1.34 root 15815: case 0x04: msdos_int_33h_0004h(); break;
1.1.1.24 root 15816: case 0x05: msdos_int_33h_0005h(); break;
15817: case 0x06: msdos_int_33h_0006h(); break;
15818: case 0x07: msdos_int_33h_0007h(); break;
15819: case 0x08: msdos_int_33h_0008h(); break;
15820: case 0x09: msdos_int_33h_0009h(); break;
1.1.1.34 root 15821: case 0x0a: break; // Define Text Cursor
1.1.1.24 root 15822: case 0x0b: msdos_int_33h_000bh(); break;
15823: case 0x0c: msdos_int_33h_000ch(); break;
1.1.1.34 root 15824: case 0x0d: break; // Light Pen Emulation On
15825: case 0x0e: break; // Light Pen Emulation Off
1.1.1.24 root 15826: case 0x0f: msdos_int_33h_000fh(); break;
1.1.1.34 root 15827: case 0x10: break; // Define Screen Region for Updating
1.1.1.24 root 15828: case 0x11: msdos_int_33h_0011h(); break;
1.1.1.34 root 15829: case 0x12: REG16(AX) = 0xffff; break; // Set Large Graphics Cursor Block
15830: case 0x13: break; // Define Double-Speed Threshold
1.1.1.24 root 15831: case 0x14: msdos_int_33h_0014h(); break;
15832: case 0x15: msdos_int_33h_0015h(); break;
15833: case 0x16: msdos_int_33h_0016h(); break;
15834: case 0x17: msdos_int_33h_0017h(); break;
1.1.1.43! root 15835: case 0x18: msdos_int_33h_0018h(); break;
! 15836: case 0x19: msdos_int_33h_0019h(); break;
1.1.1.24 root 15837: case 0x1a: msdos_int_33h_001ah(); break;
15838: case 0x1b: msdos_int_33h_001bh(); break;
15839: case 0x1d: msdos_int_33h_001dh(); break;
15840: case 0x1e: msdos_int_33h_001eh(); break;
1.1.1.34 root 15841: case 0x1f: msdos_int_33h_001fh(); break;
15842: case 0x20: msdos_int_33h_0020h(); break;
1.1.1.24 root 15843: case 0x21: msdos_int_33h_0021h(); break;
15844: case 0x22: msdos_int_33h_0022h(); break;
15845: case 0x23: msdos_int_33h_0023h(); break;
15846: case 0x24: msdos_int_33h_0024h(); break;
15847: case 0x26: msdos_int_33h_0026h(); break;
15848: case 0x2a: msdos_int_33h_002ah(); break;
1.1.1.34 root 15849: case 0x2f: break; // Mouse Hardware Reset
1.1.1.24 root 15850: case 0x31: msdos_int_33h_0031h(); break;
15851: case 0x32: msdos_int_33h_0032h(); break;
15852: default:
15853: 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));
15854: break;
15855: }
15856: break;
15857: default:
15858: 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));
15859: break;
15860: }
15861: break;
1.1.1.19 root 15862: case 0x68:
15863: // dummy interrupt for EMS (int 67h)
15864: switch(REG8(AH)) {
15865: case 0x40: msdos_int_67h_40h(); break;
15866: case 0x41: msdos_int_67h_41h(); break;
15867: case 0x42: msdos_int_67h_42h(); break;
15868: case 0x43: msdos_int_67h_43h(); break;
15869: case 0x44: msdos_int_67h_44h(); break;
15870: case 0x45: msdos_int_67h_45h(); break;
15871: case 0x46: msdos_int_67h_46h(); break;
15872: case 0x47: msdos_int_67h_47h(); break;
15873: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 15874: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
15875: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 15876: case 0x4b: msdos_int_67h_4bh(); break;
15877: case 0x4c: msdos_int_67h_4ch(); break;
15878: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 15879: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 15880: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 15881: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 15882: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 15883: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 15884: case 0x53: msdos_int_67h_53h(); break;
15885: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 15886: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
15887: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
15888: case 0x57: msdos_int_67h_57h(); break;
15889: case 0x58: msdos_int_67h_58h(); break;
1.1.1.42 root 15890: case 0x59: msdos_int_67h_59h(); break;
1.1.1.20 root 15891: case 0x5a: msdos_int_67h_5ah(); break;
15892: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
1.1.1.43! root 15893: // 0x5c: LIM EMS 4.0 - Prepare Expanded Memory Hardware For Warm Boot
! 15894: case 0x5d: msdos_int_67h_5dh(); break;
1.1.1.31 root 15895: // 0x60: EEMS - Get Physical Window Array
15896: // 0x61: EEMS - Generic Accelerator Card Support
15897: // 0x68: EEMS - Get Address of All Pge Frames om System
15898: // 0x69: EEMS - Map Page into Frame
15899: // 0x6a: EEMS - Page Mapping
15900: // 0xde: VCPI
1.1.1.30 root 15901: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 15902: default:
1.1.1.22 root 15903: 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 15904: REG8(AH) = 0x84;
15905: break;
15906: }
15907: break;
15908: #ifdef SUPPORT_XMS
15909: case 0x69:
15910: // dummy interrupt for XMS (call far)
1.1.1.28 root 15911: try {
15912: switch(REG8(AH)) {
15913: case 0x00: msdos_call_xms_00h(); break;
15914: case 0x01: msdos_call_xms_01h(); break;
15915: case 0x02: msdos_call_xms_02h(); break;
15916: case 0x03: msdos_call_xms_03h(); break;
15917: case 0x04: msdos_call_xms_04h(); break;
15918: case 0x05: msdos_call_xms_05h(); break;
15919: case 0x06: msdos_call_xms_06h(); break;
15920: case 0x07: msdos_call_xms_07h(); break;
15921: case 0x08: msdos_call_xms_08h(); break;
15922: case 0x09: msdos_call_xms_09h(); break;
15923: case 0x0a: msdos_call_xms_0ah(); break;
15924: case 0x0b: msdos_call_xms_0bh(); break;
15925: case 0x0c: msdos_call_xms_0ch(); break;
15926: case 0x0d: msdos_call_xms_0dh(); break;
15927: case 0x0e: msdos_call_xms_0eh(); break;
15928: case 0x0f: msdos_call_xms_0fh(); break;
15929: case 0x10: msdos_call_xms_10h(); break;
15930: case 0x11: msdos_call_xms_11h(); break;
15931: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 15932: #if defined(HAS_I386)
15933: case 0x88: msdos_call_xms_88h(); break;
15934: case 0x89: msdos_call_xms_89h(); break;
15935: case 0x8e: msdos_call_xms_8eh(); break;
15936: case 0x8f: msdos_call_xms_8fh(); break;
15937: #endif
1.1.1.28 root 15938: default:
15939: 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));
15940: REG16(AX) = 0x0000;
15941: REG8(BL) = 0x80; // function not implemented
15942: break;
15943: }
15944: } catch(...) {
1.1.1.19 root 15945: REG16(AX) = 0x0000;
1.1.1.28 root 15946: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 15947: }
15948: break;
15949: #endif
15950: case 0x6a:
1.1.1.24 root 15951: // irq12 (mouse)
15952: mouse_push_ax = REG16(AX);
15953: mouse_push_bx = REG16(BX);
15954: mouse_push_cx = REG16(CX);
15955: mouse_push_dx = REG16(DX);
15956: mouse_push_si = REG16(SI);
15957: mouse_push_di = REG16(DI);
15958:
1.1.1.43! root 15959: if(mouse.status_irq && mouse.call_addr.dw) {
1.1.1.24 root 15960: REG16(AX) = mouse.status_irq;
15961: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 15962: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
15963: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
1.1.1.24 root 15964: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
15965: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
15966:
15967: mem[0xfffd0 + 0x02] = 0x9a; // call far
15968: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
15969: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
15970: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
15971: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
1.1.1.43! root 15972: break;
1.1.1.24 root 15973: }
1.1.1.43! root 15974: for(int i = 0; i < 8; i++) {
! 15975: if((mouse.status_irq_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
! 15976: REG16(AX) = mouse.status_irq_alt;
! 15977: REG16(BX) = mouse.get_buttons();
! 15978: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
! 15979: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
! 15980: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
! 15981: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
! 15982:
! 15983: mem[0xfffd0 + 0x02] = 0x9a; // call far
! 15984: mem[0xfffd0 + 0x03] = mouse.call_addr_alt[i].w.l & 0xff;
! 15985: mem[0xfffd0 + 0x04] = mouse.call_addr_alt[i].w.l >> 8;
! 15986: mem[0xfffd0 + 0x05] = mouse.call_addr_alt[i].w.h & 0xff;
! 15987: mem[0xfffd0 + 0x06] = mouse.call_addr_alt[i].w.h >> 8;
! 15988: break;
! 15989: }
! 15990: }
! 15991: // invalid call addr :-(
! 15992: mem[0xfffd0 + 0x02] = 0x90; // nop
! 15993: mem[0xfffd0 + 0x03] = 0x90; // nop
! 15994: mem[0xfffd0 + 0x04] = 0x90; // nop
! 15995: mem[0xfffd0 + 0x05] = 0x90; // nop
! 15996: mem[0xfffd0 + 0x06] = 0x90; // nop
1.1.1.24 root 15997: break;
15998: case 0x6b:
15999: // end of irq12 (mouse)
16000: REG16(AX) = mouse_push_ax;
16001: REG16(BX) = mouse_push_bx;
16002: REG16(CX) = mouse_push_cx;
16003: REG16(DX) = mouse_push_dx;
16004: REG16(SI) = mouse_push_si;
16005: REG16(DI) = mouse_push_di;
16006:
16007: // EOI
16008: if((pic[1].isr &= ~(1 << 4)) == 0) {
16009: pic[0].isr &= ~(1 << 2); // master
16010: }
16011: pic_update();
16012: break;
16013: case 0x6c:
1.1.1.19 root 16014: // dummy interrupt for case map routine pointed in the country info
16015: if(REG8(AL) >= 0x80) {
16016: char tmp[2] = {0};
16017: tmp[0] = REG8(AL);
16018: my_strupr(tmp);
16019: REG8(AL) = tmp[0];
16020: }
16021: break;
1.1.1.27 root 16022: case 0x6d:
16023: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
16024: REG8(AL) = 0x86; // not supported
16025: m_CF = 1;
16026: break;
1.1.1.32 root 16027: case 0x6e:
16028: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
16029: {
16030: UINT16 code = REG16(AX);
16031: if(code & 0xf0) {
16032: code = (code & 7) | ((code & 0x10) >> 1);
16033: }
16034: for(int i = 0; i < array_length(param_error_table); i++) {
16035: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
16036: const char *message = NULL;
16037: if(active_code_page == 932) {
16038: message = param_error_table[i].message_japanese;
16039: }
16040: if(message == NULL) {
16041: message = param_error_table[i].message_english;
16042: }
16043: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
16044: strcpy((char *)(mem + WORK_TOP + 1), message);
16045:
16046: SREG(ES) = WORK_TOP >> 4;
16047: i386_load_segment_descriptor(ES);
16048: REG16(DI) = 0x0000;
16049: break;
16050: }
16051: }
16052: }
16053: break;
1.1.1.8 root 16054: case 0x70:
16055: case 0x71:
16056: case 0x72:
16057: case 0x73:
16058: case 0x74:
16059: case 0x75:
16060: case 0x76:
16061: case 0x77:
16062: // EOI
16063: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
16064: pic[0].isr &= ~(1 << 2); // master
16065: }
16066: pic_update();
16067: break;
1.1 root 16068: default:
1.1.1.22 root 16069: // 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 16070: break;
16071: }
16072:
16073: // update cursor position
16074: if(cursor_moved) {
1.1.1.36 root 16075: pcbios_update_cursor_position();
1.1 root 16076: cursor_moved = false;
16077: }
16078: }
16079:
16080: // init
16081:
16082: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
16083: {
16084: // init file handler
16085: memset(file_handler, 0, sizeof(file_handler));
16086: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
16087: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
16088: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 16089: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 16090: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 16091: #else
16092: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
16093: #endif
16094: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 16095: }
1.1.1.21 root 16096: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.37 root 16097: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
1.1.1.21 root 16098: }
1.1 root 16099: _dup2(0, DUP_STDIN);
16100: _dup2(1, DUP_STDOUT);
16101: _dup2(2, DUP_STDERR);
1.1.1.21 root 16102: _dup2(3, DUP_STDAUX);
16103: _dup2(4, DUP_STDPRN);
1.1 root 16104:
1.1.1.24 root 16105: // init mouse
16106: memset(&mouse, 0, sizeof(mouse));
1.1.1.34 root 16107: mouse.enabled = true; // from DOSBox
16108: mouse.hidden = 1; // hidden in default ???
16109: mouse.old_hidden = 1; // from DOSBox
16110: mouse.max_position.x = 8 * (scr_width - 1);
16111: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 16112: mouse.mickey.x = 8;
16113: mouse.mickey.y = 16;
16114:
1.1.1.26 root 16115: #ifdef SUPPORT_XMS
16116: // init xms
16117: msdos_xms_init();
16118: #endif
16119:
1.1 root 16120: // init process
16121: memset(process, 0, sizeof(process));
16122:
1.1.1.13 root 16123: // init dtainfo
16124: msdos_dta_info_init();
16125:
1.1 root 16126: // init memory
16127: memset(mem, 0, sizeof(mem));
16128:
16129: // bios data area
1.1.1.23 root 16130: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 16131: CONSOLE_SCREEN_BUFFER_INFO csbi;
16132: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 16133: CONSOLE_FONT_INFO cfi;
16134: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
16135:
16136: int regen = min(scr_width * scr_height * 2, 0x8000);
16137: text_vram_top_address = TEXT_VRAM_TOP;
16138: text_vram_end_address = text_vram_top_address + regen;
16139: shadow_buffer_top_address = SHADOW_BUF_TOP;
16140: shadow_buffer_end_address = shadow_buffer_top_address + regen;
16141:
16142: if(regen > 0x4000) {
16143: regen = 0x8000;
16144: vram_pages = 1;
16145: } else if(regen > 0x2000) {
16146: regen = 0x4000;
16147: vram_pages = 2;
16148: } else if(regen > 0x1000) {
16149: regen = 0x2000;
16150: vram_pages = 4;
16151: } else {
16152: regen = 0x1000;
16153: vram_pages = 8;
16154: }
1.1 root 16155:
1.1.1.25 root 16156: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
16157: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 16158: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
16159: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 16160: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.37 root 16161: *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
16162: *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32 root 16163: #ifdef EXT_BIOS_TOP
1.1.1.25 root 16164: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32 root 16165: #endif
1.1.1.26 root 16166: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1.1.33 root 16167: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
1.1.1.41 root 16168: *(UINT16 *)(mem + 0x41a) = 0x1e;
16169: *(UINT16 *)(mem + 0x41c) = 0x1e;
1.1 root 16170: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 16171: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
16172: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 16173: *(UINT16 *)(mem + 0x44e) = 0;
16174: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 16175: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 16176: *(UINT8 *)(mem + 0x460) = 7;
16177: *(UINT8 *)(mem + 0x461) = 7;
16178: *(UINT8 *)(mem + 0x462) = 0;
16179: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 16180: *(UINT8 *)(mem + 0x465) = 0x09;
16181: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.40 root 16182: *(UINT16 *)(mem + 0x472) = 0x4321; // preserve memory in cpu reset
1.1.1.41 root 16183: *(UINT16 *)(mem + 0x480) = 0x1e;
16184: *(UINT16 *)(mem + 0x482) = 0x3e;
1.1.1.14 root 16185: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
16186: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
16187: *(UINT8 *)(mem + 0x487) = 0x60;
16188: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32 root 16189: #ifdef EXT_BIOS_TOP
1.1.1.25 root 16190: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32 root 16191: #endif
1.1.1.14 root 16192:
16193: // initial screen
16194: SMALL_RECT rect;
16195: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
16196: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
16197: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
16198: for(int x = 0; x < scr_width; x++) {
16199: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
16200: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
16201: }
16202: }
1.1 root 16203:
1.1.1.19 root 16204: // init mcb
1.1 root 16205: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 16206:
16207: // iret table
16208: // note: int 2eh vector should address the routine in command.com,
16209: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
16210: // so move iret table into allocated memory block
16211: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
1.1.1.33 root 16212: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, IRET_SIZE >> 4);
1.1.1.19 root 16213: IRET_TOP = seg << 4;
16214: seg += IRET_SIZE >> 4;
1.1.1.25 root 16215: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 16216:
16217: // dummy xms/ems device
1.1.1.33 root 16218: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
1.1.1.19 root 16219: XMS_TOP = seg << 4;
16220: seg += XMS_SIZE >> 4;
16221:
16222: // environment
1.1.1.33 root 16223: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
1.1 root 16224: int env_seg = seg;
16225: int ofs = 0;
1.1.1.32 root 16226: char env_append[ENV_SIZE] = {0}, append_added = 0;
16227: char comspec_added = 0;
1.1.1.33 root 16228: char lastdrive_added = 0;
1.1.1.32 root 16229: char env_msdos_path[ENV_SIZE] = {0};
16230: char env_path[ENV_SIZE] = {0}, path_added = 0;
1.1.1.33 root 16231: char prompt_added = 0;
1.1.1.32 root 16232: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
1.1.1.33 root 16233: char tz_added = 0;
1.1.1.32 root 16234: char *path, *short_path;
16235:
16236: if((path = getenv("MSDOS_APPEND")) != NULL) {
16237: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
16238: strcpy(env_append, short_path);
16239: }
16240: }
16241: if((path = getenv("APPEND")) != NULL) {
16242: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
16243: if(env_append[0] != '\0') {
16244: strcat(env_append, ";");
16245: }
16246: strcat(env_append, short_path);
16247: }
16248: }
16249:
16250: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
16251: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
16252: strcpy(comspec_path, short_path);
16253: }
16254: }
16255: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
16256: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
16257: strcpy(comspec_path, short_path);
16258: }
16259: }
1.1 root 16260:
1.1.1.28 root 16261: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32 root 16262: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
16263: strcpy(env_msdos_path, short_path);
16264: strcpy(env_path, short_path);
1.1.1.14 root 16265: }
16266: }
1.1.1.28 root 16267: if((path = getenv("PATH")) != NULL) {
1.1.1.32 root 16268: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
16269: if(env_path[0] != '\0') {
16270: strcat(env_path, ";");
16271: }
16272: strcat(env_path, short_path);
1.1.1.9 root 16273: }
16274: }
1.1.1.32 root 16275:
16276: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
16277: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 16278: }
1.1.1.32 root 16279: for(int i = 0; i < 4; i++) {
16280: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
16281: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
16282: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
16283: strcpy(env_temp, short_path);
16284: break;
16285: }
16286: }
1.1.1.24 root 16287: }
1.1.1.32 root 16288:
1.1.1.9 root 16289: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 16290: // lower to upper
1.1.1.28 root 16291: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 16292: strcpy(tmp, *p);
16293: for(int i = 0;; i++) {
16294: if(tmp[i] == '=') {
16295: tmp[i] = '\0';
16296: sprintf(name, ";%s;", tmp);
1.1.1.25 root 16297: my_strupr(name);
1.1 root 16298: tmp[i] = '=';
16299: break;
16300: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 16301: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 16302: }
16303: }
1.1.1.33 root 16304: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
16305: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
16306: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 16307: // ignore non standard environments
16308: } else {
1.1.1.33 root 16309: if(strncmp(tmp, "APPEND=", 7) == 0) {
1.1.1.32 root 16310: if(env_append[0] != '\0') {
16311: sprintf(tmp, "APPEND=%s", env_append);
16312: } else {
16313: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
16314: }
16315: append_added = 1;
16316: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 16317: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32 root 16318: comspec_added = 1;
1.1.1.33 root 16319: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
16320: char *env = getenv("MSDOS_LASTDRIVE");
16321: if(env != NULL) {
16322: sprintf(tmp, "LASTDRIVE=%s", env);
16323: }
16324: lastdrive_added = 1;
16325: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
1.1.1.28 root 16326: if(env_msdos_path[0] != '\0') {
16327: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
16328: } else {
16329: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
16330: }
1.1.1.33 root 16331: } else if(strncmp(tmp, "PATH=", 5) == 0) {
1.1.1.28 root 16332: if(env_path[0] != '\0') {
16333: sprintf(tmp, "PATH=%s", env_path);
16334: } else {
16335: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
16336: }
1.1.1.32 root 16337: path_added = 1;
1.1.1.33 root 16338: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
16339: prompt_added = 1;
1.1.1.28 root 16340: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
16341: if(env_temp[0] != '\0') {
16342: sprintf(tmp, "TEMP=%s", env_temp);
16343: } else {
16344: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
16345: }
1.1.1.32 root 16346: temp_added = 1;
1.1.1.33 root 16347: } else if(strncmp(tmp, "TMP=", 4) == 0) {
1.1.1.28 root 16348: if(env_temp[0] != '\0') {
16349: sprintf(tmp, "TMP=%s", env_temp);
16350: } else {
16351: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 16352: }
1.1.1.32 root 16353: tmp_added = 1;
1.1.1.33 root 16354: } else if(strncmp(tmp, "TZ=", 3) == 0) {
16355: char *env = getenv("MSDOS_TZ");
16356: if(env != NULL) {
16357: sprintf(tmp, "TZ=%s", env);
16358: }
16359: tz_added = 1;
1.1 root 16360: }
16361: int len = strlen(tmp);
1.1.1.14 root 16362: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 16363: fatalerror("too many environments\n");
16364: }
16365: memcpy(mem + (seg << 4) + ofs, tmp, len);
16366: ofs += len + 1;
16367: }
16368: }
1.1.1.32 root 16369: if(!append_added && env_append[0] != '\0') {
16370: #define SET_ENV(name, value) { \
16371: char tmp[ENV_SIZE]; \
16372: sprintf(tmp, "%s=%s", name, value); \
16373: int len = strlen(tmp); \
16374: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
16375: fatalerror("too many environments\n"); \
16376: } \
16377: memcpy(mem + (seg << 4) + ofs, tmp, len); \
16378: ofs += len + 1; \
16379: }
16380: SET_ENV("APPEND", env_append);
16381: }
16382: if(!comspec_added) {
16383: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
16384: }
1.1.1.33 root 16385: if(!lastdrive_added) {
16386: SET_ENV("LASTDRIVE", "Z");
16387: }
1.1.1.32 root 16388: if(!path_added) {
16389: SET_ENV("PATH", env_path);
16390: }
1.1.1.33 root 16391: if(!prompt_added) {
16392: SET_ENV("PROMPT", "$P$G");
16393: }
1.1.1.32 root 16394: if(!temp_added) {
16395: SET_ENV("TEMP", env_temp);
16396: }
16397: if(!tmp_added) {
16398: SET_ENV("TMP", env_temp);
16399: }
1.1.1.33 root 16400: if(!tz_added) {
16401: TIME_ZONE_INFORMATION tzi;
16402: HKEY hKey, hSubKey;
16403: char tzi_std_name[64];
16404: char tz_std[8] = "GMT";
16405: char tz_dlt[8] = "GST";
16406: char tz_value[32];
16407:
16408: // timezone name from GetTimeZoneInformation may not be english
16409: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
16410: setlocale(LC_CTYPE, "");
16411: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
16412:
16413: // get english timezone name from registry
16414: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
16415: for(DWORD i = 0; !tz_added; i++) {
16416: char reg_name[256], sub_key[1024], std_name[256];
16417: DWORD size;
16418: FILETIME ftTime;
16419: LONG result = RegEnumKeyEx(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
16420:
16421: if(result == ERROR_SUCCESS) {
16422: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
16423: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
16424: if(RegQueryValueEx(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
16425: // search english timezone name from table
1.1.1.37 root 16426: if(strcmp(std_name, tzi_std_name) == 0) {
1.1.1.33 root 16427: for(int j = 0; j < array_length(tz_table); j++) {
16428: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
16429: if(tz_table[j].std != NULL) {
16430: strcpy(tz_std, tz_table[j].std);
16431: }
16432: if(tz_table[j].dlt != NULL) {
16433: strcpy(tz_dlt, tz_table[j].dlt);
16434: }
16435: tz_added = 1;
16436: break;
16437: }
16438: }
16439: }
16440: }
16441: RegCloseKey(hSubKey);
16442: }
16443: } else if(result == ERROR_NO_MORE_ITEMS) {
16444: break;
16445: }
16446: }
16447: RegCloseKey(hKey);
16448: }
16449: if((tzi.Bias % 60) != 0) {
16450: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
16451: } else {
16452: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
16453: }
16454: if(daylight) {
16455: strcat(tz_value, tz_dlt);
16456: }
16457: SET_ENV("TZ", tz_value);
16458: }
1.1 root 16459: seg += (ENV_SIZE >> 4);
16460:
16461: // psp
1.1.1.33 root 16462: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
1.1 root 16463: current_psp = seg;
1.1.1.35 root 16464: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
16465: psp->parent_psp = current_psp;
1.1 root 16466: seg += (PSP_SIZE >> 4);
16467:
1.1.1.19 root 16468: // first free mcb in conventional memory
1.1.1.33 root 16469: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 16470: first_mcb = seg;
16471:
1.1.1.19 root 16472: // dummy mcb to link to umb
1.1.1.33 root 16473: #if 0
1.1.1.39 root 16474: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); // link umb
1.1.1.33 root 16475: #else
1.1.1.39 root 16476: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); // unlink umb
1.1.1.33 root 16477: #endif
1.1.1.19 root 16478:
16479: // first free mcb in upper memory block
1.1.1.8 root 16480: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 16481:
1.1.1.29 root 16482: #ifdef SUPPORT_HMA
16483: // first free mcb in high memory area
16484: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
16485: #endif
16486:
1.1.1.26 root 16487: // interrupt vector
16488: for(int i = 0; i < 0x80; i++) {
16489: *(UINT16 *)(mem + 4 * i + 0) = i;
16490: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
16491: }
1.1.1.35 root 16492: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffd:0018 irq0 (system timer)
1.1.1.26 root 16493: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
16494: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
16495: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
16496: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
16497: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
16498: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
16499: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
16500:
1.1.1.29 root 16501: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 16502: static const struct {
16503: UINT16 attributes;
16504: char *dev_name;
16505: } dummy_devices[] = {
16506: {0x8013, "CON "},
16507: {0x8000, "AUX "},
16508: {0xa0c0, "PRN "},
16509: {0x8008, "CLOCK$ "},
16510: {0x8000, "COM1 "},
16511: {0xa0c0, "LPT1 "},
16512: {0xa0c0, "LPT2 "},
16513: {0xa0c0, "LPT3 "},
16514: {0x8000, "COM2 "},
16515: {0x8000, "COM3 "},
16516: {0x8000, "COM4 "},
1.1.1.30 root 16517: // {0xc000, "CONFIG$ "},
16518: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 16519: };
16520: static const UINT8 dummy_device_routine[] = {
16521: // from NUL device of Windows 98 SE
16522: // or word ptr ES:[BX+03],0100
16523: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
16524: // retf
16525: 0xcb,
16526: };
1.1.1.29 root 16527: device_t *last = NULL;
1.1.1.32 root 16528: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 16529: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 16530: device->next_driver.w.l = 22 + 18 * (i + 1);
16531: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 16532: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 16533: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
16534: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 16535: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 16536: last = device;
16537: }
16538: if(last != NULL) {
16539: last->next_driver.w.l = 0;
16540: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 16541: }
1.1.1.29 root 16542: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 16543:
1.1.1.25 root 16544: // dos info
16545: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
16546: dos_info->magic_word = 1;
16547: dos_info->first_mcb = MEMORY_TOP >> 4;
16548: dos_info->first_dpb.w.l = 0;
16549: dos_info->first_dpb.w.h = DPB_TOP >> 4;
16550: dos_info->first_sft.w.l = 0;
16551: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.41 root 16552: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 4th device in IO.SYS
1.1.1.25 root 16553: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 16554: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 16555: dos_info->con_device.w.h = DEVICE_TOP >> 4;
16556: dos_info->max_sector_len = 512;
16557: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
16558: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
16559: dos_info->cds.w.l = 0;
16560: dos_info->cds.w.h = CDS_TOP >> 4;
16561: dos_info->fcb_table.w.l = 0;
16562: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
16563: dos_info->last_drive = 'Z' - 'A' + 1;
16564: dos_info->buffers_x = 20;
16565: dos_info->buffers_y = 0;
16566: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 16567: dos_info->nul_device.next_driver.w.l = 22;
16568: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 16569: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 16570: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
16571: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 16572: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
16573: dos_info->disk_buf_heads.w.l = 0;
16574: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.39 root 16575: dos_info->umb_linked = (((mcb_t *)(mem + MEMORY_END - 16))->mz == 'M' ? 0x01 : 0x00);
1.1.1.25 root 16576: dos_info->first_umb_fcb = UMB_TOP >> 4;
16577: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 16578: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 16579:
16580: char *env;
16581: if((env = getenv("LASTDRIVE")) != NULL) {
16582: if(env[0] >= 'A' && env[0] <= 'Z') {
16583: dos_info->last_drive = env[0] - 'A' + 1;
16584: } else if(env[0] >= 'a' && env[0] <= 'z') {
16585: dos_info->last_drive = env[0] - 'a' + 1;
16586: }
16587: }
16588: if((env = getenv("windir")) != NULL) {
16589: if(env[0] >= 'A' && env[0] <= 'Z') {
16590: dos_info->boot_drive = env[0] - 'A' + 1;
16591: } else if(env[0] >= 'a' && env[0] <= 'z') {
16592: dos_info->boot_drive = env[0] - 'a' + 1;
16593: }
16594: }
16595: #if defined(HAS_I386)
16596: dos_info->i386_or_later = 1;
16597: #else
16598: dos_info->i386_or_later = 0;
16599: #endif
16600: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
16601:
1.1.1.27 root 16602: // ems (int 67h) and xms
1.1.1.25 root 16603: device_t *xms_device = (device_t *)(mem + XMS_TOP);
16604: xms_device->next_driver.w.l = 0xffff;
16605: xms_device->next_driver.w.h = 0xffff;
16606: xms_device->attributes = 0xc000;
1.1.1.29 root 16607: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
16608: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 16609: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
16610:
1.1.1.26 root 16611: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
16612: mem[XMS_TOP + 0x13] = 0x68;
16613: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 16614: #ifdef SUPPORT_XMS
16615: if(support_xms) {
1.1.1.26 root 16616: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
16617: mem[XMS_TOP + 0x16] = 0x69;
16618: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 16619: } else
16620: #endif
1.1.1.26 root 16621: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 16622: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 16623:
1.1.1.26 root 16624: // irq12 routine (mouse)
1.1.1.24 root 16625: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
16626: mem[0xfffd0 + 0x01] = 0x6a;
16627: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
16628: mem[0xfffd0 + 0x03] = 0xff;
16629: mem[0xfffd0 + 0x04] = 0xff;
16630: mem[0xfffd0 + 0x05] = 0xff;
16631: mem[0xfffd0 + 0x06] = 0xff;
16632: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
16633: mem[0xfffd0 + 0x08] = 0x6b;
16634: mem[0xfffd0 + 0x09] = 0xcf; // iret
16635:
1.1.1.27 root 16636: // case map routine
16637: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
16638: mem[0xfffd0 + 0x0b] = 0x6c;
16639: mem[0xfffd0 + 0x0c] = 0xcb; // retf
16640:
16641: // font read routine
16642: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
16643: mem[0xfffd0 + 0x0e] = 0x6d;
16644: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 16645:
1.1.1.32 root 16646: // error message read routine
16647: mem[0xfffd0 + 0x10] = 0xcd; // int 6eh (dummy)
16648: mem[0xfffd0 + 0x11] = 0x6e;
16649: mem[0xfffd0 + 0x12] = 0xcb; // retf
16650:
1.1.1.35 root 16651: // dummy loop to wait BIOS/DOS service is done
16652: mem[0xfffd0 + 0x13] = 0xe6; // out f7h, al
16653: mem[0xfffd0 + 0x14] = 0xf7;
16654: mem[0xfffd0 + 0x15] = 0x78; // js/jns -4
16655: mem[0xfffd0 + 0x16] = 0xfc;
16656: mem[0xfffd0 + 0x17] = 0xcb; // retf
16657:
1.1.1.26 root 16658: // irq0 routine (system time)
1.1.1.35 root 16659: mem[0xfffd0 + 0x18] = 0xcd; // int 1ch
16660: mem[0xfffd0 + 0x19] = 0x1c;
16661: mem[0xfffd0 + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008
16662: mem[0xfffd0 + 0x1b] = 0x08;
16663: mem[0xfffd0 + 0x1c] = 0x00;
16664: mem[0xfffd0 + 0x1d] = ((IRET_TOP >> 4) ) & 0xff;
16665: mem[0xfffd0 + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 16666:
1.1.1.26 root 16667: // boot routine
1.1 root 16668: mem[0xffff0] = 0xf4; // halt
16669: mem[0xffff1] = 0xcd; // int 21h
16670: mem[0xffff2] = 0x21;
16671: mem[0xffff3] = 0xcb; // retf
16672:
1.1.1.24 root 16673: mem[0xffff5] = '0'; // rom date
16674: mem[0xffff6] = '2';
16675: mem[0xffff7] = '/';
16676: mem[0xffff8] = '2';
16677: mem[0xffff9] = '2';
16678: mem[0xffffa] = '/';
16679: mem[0xffffb] = '0';
16680: mem[0xffffc] = '6';
16681: mem[0xffffe] = 0xfc; // machine id
16682: mem[0xfffff] = 0x00;
16683:
1.1 root 16684: // param block
16685: // + 0: param block (22bytes)
16686: // +24: fcb1/2 (20bytes)
16687: // +44: command tail (128bytes)
16688: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
16689: param->env_seg = 0;
16690: param->cmd_line.w.l = 44;
16691: param->cmd_line.w.h = (WORK_TOP >> 4);
16692: param->fcb1.w.l = 24;
16693: param->fcb1.w.h = (WORK_TOP >> 4);
16694: param->fcb2.w.l = 24;
16695: param->fcb2.w.h = (WORK_TOP >> 4);
16696:
16697: memset(mem + WORK_TOP + 24, 0x20, 20);
16698:
16699: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
16700: if(argc > 1) {
16701: sprintf(cmd_line->cmd, " %s", argv[1]);
16702: for(int i = 2; i < argc; i++) {
16703: char tmp[128];
16704: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
16705: strcpy(cmd_line->cmd, tmp);
16706: }
16707: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
16708: } else {
16709: cmd_line->len = 0;
16710: }
16711: cmd_line->cmd[cmd_line->len] = 0x0d;
16712:
16713: // system file table
1.1.1.21 root 16714: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
16715: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 16716:
1.1.1.19 root 16717: // disk buffer header (from DOSBox)
16718: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
16719: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
16720: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
16721: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
16722: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
16723:
1.1 root 16724: // current directory structure
16725: msdos_cds_update(_getdrive() - 1);
16726:
16727: // fcb table
16728: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 16729: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 16730:
1.1.1.41 root 16731: // drive parameter block
1.1.1.42 root 16732: for(int i = 0; i < 2; i++) {
1.1.1.43! root 16733: // may be a floppy drive
1.1.1.41 root 16734: dpb_t *dpb = (dpb_t *)(mem + DPB_TOP + sizeof(dpb_t) * i);
16735: dpb->drive_num = i;
16736: dpb->unit_num = i;
1.1.1.43! root 16737: dpb->next_dpb_ofs = /*(i == 25) ? 0xffff : */sizeof(dpb_t) * (i + 1);
! 16738: dpb->next_dpb_seg = /*(i == 25) ? 0xffff : */DPB_TOP >> 4;
1.1.1.42 root 16739: }
16740: for(int i = 2; i < 26; i++) {
16741: UINT16 seg, ofs;
16742: msdos_drive_param_block_update(i, &seg, &ofs, 1);
1.1.1.41 root 16743: }
16744:
1.1.1.17 root 16745: // nls stuff
16746: msdos_nls_tables_init();
1.1 root 16747:
16748: // execute command
1.1.1.28 root 16749: try {
16750: if(msdos_process_exec(argv[0], param, 0)) {
16751: fatalerror("'%s' not found\n", argv[0]);
16752: }
16753: } catch(...) {
16754: // we should not reach here :-(
16755: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 16756: }
16757: retval = 0;
16758: return(0);
16759: }
16760:
16761: #define remove_std_file(path) { \
16762: int fd = _open(path, _O_RDONLY | _O_BINARY); \
16763: if(fd != -1) { \
16764: _lseek(fd, 0, SEEK_END); \
16765: int size = _tell(fd); \
16766: _close(fd); \
16767: if(size == 0) { \
16768: remove(path); \
16769: } \
16770: } \
16771: }
16772:
16773: void msdos_finish()
16774: {
16775: for(int i = 0; i < MAX_FILES; i++) {
16776: if(file_handler[i].valid) {
16777: _close(i);
16778: }
16779: }
1.1.1.21 root 16780: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 16781: remove_std_file("stdaux.txt");
1.1.1.21 root 16782: #endif
1.1.1.30 root 16783: #ifdef SUPPORT_XMS
16784: msdos_xms_finish();
16785: #endif
1.1 root 16786: msdos_dbcs_table_finish();
16787: }
16788:
16789: /* ----------------------------------------------------------------------------
16790: PC/AT hardware emulation
16791: ---------------------------------------------------------------------------- */
16792:
16793: void hardware_init()
16794: {
1.1.1.3 root 16795: CPU_INIT_CALL(CPU_MODEL);
1.1 root 16796: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 16797: m_IF = 1;
1.1.1.3 root 16798: #if defined(HAS_I386)
1.1 root 16799: cpu_type = (REG32(EDX) >> 8) & 0x0f;
16800: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 16801: #endif
16802: i386_set_a20_line(0);
1.1.1.14 root 16803:
1.1.1.19 root 16804: ems_init();
1.1.1.25 root 16805: dma_init();
1.1 root 16806: pic_init();
1.1.1.25 root 16807: pio_init();
1.1.1.8 root 16808: #ifdef PIT_ALWAYS_RUNNING
16809: pit_init();
16810: #else
1.1 root 16811: pit_active = 0;
16812: #endif
1.1.1.25 root 16813: sio_init();
1.1.1.8 root 16814: cmos_init();
16815: kbd_init();
1.1 root 16816: }
16817:
1.1.1.10 root 16818: void hardware_finish()
16819: {
16820: #if defined(HAS_I386)
16821: vtlb_free(m_vtlb);
16822: #endif
1.1.1.19 root 16823: ems_finish();
1.1.1.37 root 16824: pio_finish();
1.1.1.25 root 16825: sio_finish();
1.1.1.10 root 16826: }
16827:
1.1.1.28 root 16828: void hardware_release()
16829: {
16830: // release hardware resources when this program will be terminated abnormally
16831: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 16832: if(fp_debug_log != NULL) {
16833: fclose(fp_debug_log);
16834: fp_debug_log = NULL;
1.1.1.28 root 16835: }
16836: #endif
16837: #if defined(HAS_I386)
16838: vtlb_free(m_vtlb);
16839: #endif
16840: ems_release();
1.1.1.37 root 16841: pio_release();
1.1.1.28 root 16842: sio_release();
16843: }
16844:
1.1 root 16845: void hardware_run()
16846: {
1.1.1.22 root 16847: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 16848: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.33 root 16849: fp_debug_log = fopen("debug.log", "w");
1.1.1.22 root 16850: #endif
1.1.1.3 root 16851: while(!m_halted) {
16852: #if defined(HAS_I386)
1.1 root 16853: CPU_EXECUTE_CALL(i386);
1.1.1.14 root 16854: if(m_eip != m_prev_eip) {
1.1.1.35 root 16855: idle_ops++;
16856: }
1.1.1.14 root 16857: #else
1.1.1.35 root 16858: CPU_EXECUTE_CALL(CPU_MODEL);
1.1.1.14 root 16859: if(m_pc != m_prevpc) {
1.1.1.35 root 16860: idle_ops++;
1.1.1.14 root 16861: }
1.1.1.35 root 16862: #endif
16863: if(++update_ops == UPDATE_OPS) {
1.1 root 16864: hardware_update();
1.1.1.35 root 16865: update_ops = 0;
1.1 root 16866: }
16867: }
1.1.1.22 root 16868: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 16869: if(fp_debug_log != NULL) {
16870: fclose(fp_debug_log);
16871: fp_debug_log = NULL;
1.1.1.28 root 16872: }
1.1.1.22 root 16873: #endif
1.1 root 16874: }
16875:
16876: void hardware_update()
16877: {
1.1.1.8 root 16878: static UINT32 prev_time = 0;
16879: UINT32 cur_time = timeGetTime();
16880:
16881: if(prev_time != cur_time) {
16882: // update pit and raise irq0
16883: #ifndef PIT_ALWAYS_RUNNING
16884: if(pit_active)
16885: #endif
16886: {
16887: if(pit_run(0, cur_time)) {
16888: pic_req(0, 0, 1);
16889: }
16890: pit_run(1, cur_time);
16891: pit_run(2, cur_time);
16892: }
1.1.1.24 root 16893:
1.1.1.25 root 16894: // update sio and raise irq4/3
1.1.1.29 root 16895: for(int c = 0; c < 4; c++) {
1.1.1.25 root 16896: sio_update(c);
16897: }
16898:
1.1.1.24 root 16899: // update keyboard and mouse
1.1.1.14 root 16900: static UINT32 prev_tick = 0;
16901: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 16902:
1.1.1.14 root 16903: if(prev_tick != cur_tick) {
16904: // update keyboard flags
16905: UINT8 state;
1.1.1.24 root 16906: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
16907: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
16908: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
16909: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
16910: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
16911: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
16912: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
16913: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 16914: mem[0x417] = state;
16915: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
16916: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
16917: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
16918: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 16919: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
16920: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 16921: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
16922: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
16923: mem[0x418] = state;
16924:
1.1.1.24 root 16925: // update console input if needed
1.1.1.34 root 16926: if(!key_changed || mouse.hidden == 0) {
1.1.1.24 root 16927: update_console_input();
16928: }
16929:
16930: // raise irq1 if key is pressed/released
16931: if(key_changed) {
1.1.1.8 root 16932: pic_req(0, 1, 1);
1.1.1.24 root 16933: key_changed = false;
16934: }
16935:
16936: // raise irq12 if mouse status is changed
1.1.1.43! root 16937: if((mouse.status & mouse.call_mask) && mouse.call_addr.dw) {
! 16938: mouse.status_irq = mouse.status & mouse.call_mask;
! 16939: mouse.status_irq_alt = 0; // ???
1.1.1.24 root 16940: mouse.status &= ~mouse.call_mask;
1.1.1.43! root 16941: pic_req(1, 4, 1);
! 16942: } else {
! 16943: for(int i = 0; i < 8; i++) {
! 16944: if((mouse.status_alt & (1 << i)) && mouse.call_addr_alt[i].dw) {
! 16945: mouse.status_irq = 0; // ???
! 16946: mouse.status_irq_alt = 0;
! 16947: for(int j = 0; j < 8; j++) {
! 16948: if((mouse.status_alt & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) {
! 16949: mouse.status_irq_alt |= (1 << j);
! 16950: mouse.status_alt &= ~(1 << j);
! 16951: }
! 16952: }
! 16953: pic_req(1, 4, 1);
! 16954: break;
! 16955: }
! 16956: }
1.1.1.8 root 16957: }
1.1.1.24 root 16958:
1.1.1.14 root 16959: prev_tick = cur_tick;
1.1.1.8 root 16960: }
1.1.1.24 root 16961:
1.1.1.19 root 16962: // update daily timer counter
16963: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 16964:
1.1.1.8 root 16965: prev_time = cur_time;
1.1 root 16966: }
16967: }
16968:
1.1.1.19 root 16969: // ems
16970:
16971: void ems_init()
16972: {
16973: memset(ems_handles, 0, sizeof(ems_handles));
16974: memset(ems_pages, 0, sizeof(ems_pages));
16975: free_ems_pages = MAX_EMS_PAGES;
16976: }
16977:
16978: void ems_finish()
16979: {
1.1.1.28 root 16980: ems_release();
16981: }
16982:
16983: void ems_release()
16984: {
1.1.1.31 root 16985: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 16986: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 16987: free(ems_handles[i].buffer);
16988: ems_handles[i].buffer = NULL;
16989: }
16990: }
16991: }
16992:
16993: void ems_allocate_pages(int handle, int pages)
16994: {
16995: if(pages > 0) {
16996: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
16997: } else {
16998: ems_handles[handle].buffer = NULL;
16999: }
17000: ems_handles[handle].pages = pages;
17001: ems_handles[handle].allocated = true;
17002: free_ems_pages -= pages;
17003: }
17004:
17005: void ems_reallocate_pages(int handle, int pages)
17006: {
17007: if(ems_handles[handle].allocated) {
17008: if(ems_handles[handle].pages != pages) {
17009: UINT8 *new_buffer = NULL;
17010:
17011: if(pages > 0) {
17012: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
17013: }
1.1.1.32 root 17014: if(ems_handles[handle].buffer != NULL) {
17015: if(new_buffer != NULL) {
1.1.1.19 root 17016: if(pages > ems_handles[handle].pages) {
17017: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
17018: } else {
17019: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
17020: }
17021: }
17022: free(ems_handles[handle].buffer);
17023: ems_handles[handle].buffer = NULL;
17024: }
17025: free_ems_pages += ems_handles[handle].pages;
17026:
17027: ems_handles[handle].buffer = new_buffer;
17028: ems_handles[handle].pages = pages;
17029: free_ems_pages -= pages;
17030: }
17031: } else {
17032: ems_allocate_pages(handle, pages);
17033: }
17034: }
17035:
17036: void ems_release_pages(int handle)
17037: {
17038: if(ems_handles[handle].allocated) {
1.1.1.32 root 17039: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 17040: free(ems_handles[handle].buffer);
17041: ems_handles[handle].buffer = NULL;
17042: }
17043: free_ems_pages += ems_handles[handle].pages;
17044: ems_handles[handle].allocated = false;
17045: }
17046: }
17047:
17048: void ems_map_page(int physical, int handle, int logical)
17049: {
17050: if(ems_pages[physical].mapped) {
17051: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
17052: return;
17053: }
17054: ems_unmap_page(physical);
17055: }
1.1.1.32 root 17056: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 17057: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
17058: }
17059: ems_pages[physical].handle = handle;
17060: ems_pages[physical].page = logical;
17061: ems_pages[physical].mapped = true;
17062: }
17063:
17064: void ems_unmap_page(int physical)
17065: {
17066: if(ems_pages[physical].mapped) {
17067: int handle = ems_pages[physical].handle;
17068: int logical = ems_pages[physical].page;
17069:
1.1.1.32 root 17070: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 17071: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
17072: }
17073: ems_pages[physical].mapped = false;
17074: }
17075: }
17076:
1.1.1.25 root 17077: // dma
1.1 root 17078:
1.1.1.25 root 17079: void dma_init()
1.1 root 17080: {
1.1.1.26 root 17081: memset(dma, 0, sizeof(dma));
1.1.1.25 root 17082: for(int c = 0; c < 2; c++) {
1.1.1.26 root 17083: // for(int ch = 0; ch < 4; ch++) {
17084: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
17085: // }
1.1.1.25 root 17086: dma_reset(c);
17087: }
1.1 root 17088: }
17089:
1.1.1.25 root 17090: void dma_reset(int c)
1.1 root 17091: {
1.1.1.25 root 17092: dma[c].low_high = false;
17093: dma[c].cmd = dma[c].req = dma[c].tc = 0;
17094: dma[c].mask = 0xff;
17095: }
17096:
17097: void dma_write(int c, UINT32 addr, UINT8 data)
17098: {
17099: int ch = (addr >> 1) & 3;
17100: UINT8 bit = 1 << (data & 3);
17101:
17102: switch(addr & 0x0f) {
17103: case 0x00: case 0x02: case 0x04: case 0x06:
17104: if(dma[c].low_high) {
17105: dma[c].ch[ch].bareg.b.h = data;
1.1 root 17106: } else {
1.1.1.25 root 17107: dma[c].ch[ch].bareg.b.l = data;
17108: }
17109: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
17110: dma[c].low_high = !dma[c].low_high;
17111: break;
17112: case 0x01: case 0x03: case 0x05: case 0x07:
17113: if(dma[c].low_high) {
17114: dma[c].ch[ch].bcreg.b.h = data;
17115: } else {
17116: dma[c].ch[ch].bcreg.b.l = data;
17117: }
17118: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
17119: dma[c].low_high = !dma[c].low_high;
17120: break;
17121: case 0x08:
17122: // command register
17123: dma[c].cmd = data;
17124: break;
17125: case 0x09:
17126: // dma[c].request register
17127: if(data & 4) {
17128: if(!(dma[c].req & bit)) {
17129: dma[c].req |= bit;
17130: // dma_run(c, ch);
17131: }
17132: } else {
17133: dma[c].req &= ~bit;
17134: }
17135: break;
17136: case 0x0a:
17137: // single mask register
17138: if(data & 4) {
17139: dma[c].mask |= bit;
17140: } else {
17141: dma[c].mask &= ~bit;
17142: }
17143: break;
17144: case 0x0b:
17145: // mode register
17146: dma[c].ch[data & 3].mode = data;
17147: break;
17148: case 0x0c:
17149: dma[c].low_high = false;
17150: break;
17151: case 0x0d:
17152: // clear master
17153: dma_reset(c);
17154: break;
17155: case 0x0e:
17156: // clear mask register
17157: dma[c].mask = 0;
17158: break;
17159: case 0x0f:
17160: // all mask register
17161: dma[c].mask = data & 0x0f;
17162: break;
17163: }
17164: }
17165:
17166: UINT8 dma_read(int c, UINT32 addr)
17167: {
17168: int ch = (addr >> 1) & 3;
17169: UINT8 val = 0xff;
17170:
17171: switch(addr & 0x0f) {
17172: case 0x00: case 0x02: case 0x04: case 0x06:
17173: if(dma[c].low_high) {
17174: val = dma[c].ch[ch].areg.b.h;
17175: } else {
17176: val = dma[c].ch[ch].areg.b.l;
17177: }
17178: dma[c].low_high = !dma[c].low_high;
17179: return(val);
17180: case 0x01: case 0x03: case 0x05: case 0x07:
17181: if(dma[c].low_high) {
17182: val = dma[c].ch[ch].creg.b.h;
17183: } else {
17184: val = dma[c].ch[ch].creg.b.l;
17185: }
17186: dma[c].low_high = !dma[c].low_high;
17187: return(val);
17188: case 0x08:
17189: // status register
17190: val = (dma[c].req << 4) | dma[c].tc;
17191: dma[c].tc = 0;
17192: return(val);
17193: case 0x0d:
1.1.1.26 root 17194: // temporary register (intel 82374 does not support)
1.1.1.25 root 17195: return(dma[c].tmp & 0xff);
1.1.1.26 root 17196: case 0x0f:
17197: // mask register (intel 82374 does support)
17198: return(dma[c].mask);
1.1.1.25 root 17199: }
17200: return(0xff);
17201: }
17202:
17203: void dma_page_write(int c, int ch, UINT8 data)
17204: {
17205: dma[c].ch[ch].pagereg = data;
17206: }
17207:
17208: UINT8 dma_page_read(int c, int ch)
17209: {
17210: return(dma[c].ch[ch].pagereg);
17211: }
17212:
17213: void dma_run(int c, int ch)
17214: {
17215: UINT8 bit = 1 << ch;
17216:
17217: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
17218: // execute dma
17219: while(dma[c].req & bit) {
17220: if(ch == 0 && (dma[c].cmd & 0x01)) {
17221: // memory -> memory
17222: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
17223: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
17224:
17225: if(c == 0) {
17226: dma[c].tmp = read_byte(saddr);
17227: write_byte(daddr, dma[c].tmp);
17228: } else {
17229: dma[c].tmp = read_word(saddr << 1);
17230: write_word(daddr << 1, dma[c].tmp);
17231: }
17232: if(!(dma[c].cmd & 0x02)) {
17233: if(dma[c].ch[0].mode & 0x20) {
17234: dma[c].ch[0].areg.w--;
17235: if(dma[c].ch[0].areg.w == 0xffff) {
17236: dma[c].ch[0].pagereg--;
17237: }
17238: } else {
17239: dma[c].ch[0].areg.w++;
17240: if(dma[c].ch[0].areg.w == 0) {
17241: dma[c].ch[0].pagereg++;
17242: }
17243: }
17244: }
17245: if(dma[c].ch[1].mode & 0x20) {
17246: dma[c].ch[1].areg.w--;
17247: if(dma[c].ch[1].areg.w == 0xffff) {
17248: dma[c].ch[1].pagereg--;
17249: }
17250: } else {
17251: dma[c].ch[1].areg.w++;
17252: if(dma[c].ch[1].areg.w == 0) {
17253: dma[c].ch[1].pagereg++;
17254: }
17255: }
17256:
17257: // check dma condition
17258: if(dma[c].ch[0].creg.w-- == 0) {
17259: if(dma[c].ch[0].mode & 0x10) {
17260: // self initialize
17261: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
17262: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
17263: } else {
17264: // dma[c].mask |= bit;
17265: }
17266: }
17267: if(dma[c].ch[1].creg.w-- == 0) {
17268: // terminal count
17269: if(dma[c].ch[1].mode & 0x10) {
17270: // self initialize
17271: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
17272: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
17273: } else {
17274: dma[c].mask |= bit;
17275: }
17276: dma[c].req &= ~bit;
17277: dma[c].tc |= bit;
17278: }
17279: } else {
17280: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
17281:
17282: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
17283: // verify
17284: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
17285: // io -> memory
17286: if(c == 0) {
17287: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
17288: write_byte(addr, dma[c].tmp);
17289: } else {
17290: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
17291: write_word(addr << 1, dma[c].tmp);
17292: }
17293: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
17294: // memory -> io
17295: if(c == 0) {
17296: dma[c].tmp = read_byte(addr);
17297: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
17298: } else {
17299: dma[c].tmp = read_word(addr << 1);
17300: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
17301: }
17302: }
17303: if(dma[c].ch[ch].mode & 0x20) {
17304: dma[c].ch[ch].areg.w--;
17305: if(dma[c].ch[ch].areg.w == 0xffff) {
17306: dma[c].ch[ch].pagereg--;
17307: }
17308: } else {
17309: dma[c].ch[ch].areg.w++;
17310: if(dma[c].ch[ch].areg.w == 0) {
17311: dma[c].ch[ch].pagereg++;
17312: }
17313: }
17314:
17315: // check dma condition
17316: if(dma[c].ch[ch].creg.w-- == 0) {
17317: // terminal count
17318: if(dma[c].ch[ch].mode & 0x10) {
17319: // self initialize
17320: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
17321: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
17322: } else {
17323: dma[c].mask |= bit;
17324: }
17325: dma[c].req &= ~bit;
17326: dma[c].tc |= bit;
17327: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
17328: // single mode
17329: break;
17330: }
17331: }
17332: }
17333: }
17334: }
17335:
17336: // pic
17337:
17338: void pic_init()
17339: {
17340: memset(pic, 0, sizeof(pic));
17341: pic[0].imr = pic[1].imr = 0xff;
17342:
17343: // from bochs bios
17344: pic_write(0, 0, 0x11); // icw1 = 11h
17345: pic_write(0, 1, 0x08); // icw2 = 08h
17346: pic_write(0, 1, 0x04); // icw3 = 04h
17347: pic_write(0, 1, 0x01); // icw4 = 01h
17348: pic_write(0, 1, 0xb8); // ocw1 = b8h
17349: pic_write(1, 0, 0x11); // icw1 = 11h
17350: pic_write(1, 1, 0x70); // icw2 = 70h
17351: pic_write(1, 1, 0x02); // icw3 = 02h
17352: pic_write(1, 1, 0x01); // icw4 = 01h
17353: }
17354:
17355: void pic_write(int c, UINT32 addr, UINT8 data)
17356: {
17357: if(addr & 1) {
17358: if(pic[c].icw2_r) {
17359: // icw2
17360: pic[c].icw2 = data;
17361: pic[c].icw2_r = 0;
17362: } else if(pic[c].icw3_r) {
17363: // icw3
17364: pic[c].icw3 = data;
17365: pic[c].icw3_r = 0;
17366: } else if(pic[c].icw4_r) {
17367: // icw4
17368: pic[c].icw4 = data;
17369: pic[c].icw4_r = 0;
17370: } else {
17371: // ocw1
1.1 root 17372: pic[c].imr = data;
17373: }
17374: } else {
17375: if(data & 0x10) {
17376: // icw1
17377: pic[c].icw1 = data;
17378: pic[c].icw2_r = 1;
17379: pic[c].icw3_r = (data & 2) ? 0 : 1;
17380: pic[c].icw4_r = data & 1;
17381: pic[c].irr = 0;
17382: pic[c].isr = 0;
17383: pic[c].imr = 0;
17384: pic[c].prio = 0;
17385: if(!(pic[c].icw1 & 1)) {
17386: pic[c].icw4 = 0;
17387: }
17388: pic[c].ocw3 = 0;
17389: } else if(data & 8) {
17390: // ocw3
17391: if(!(data & 2)) {
17392: data = (data & ~1) | (pic[c].ocw3 & 1);
17393: }
17394: if(!(data & 0x40)) {
17395: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
17396: }
17397: pic[c].ocw3 = data;
17398: } else {
17399: // ocw2
17400: int level = 0;
17401: if(data & 0x40) {
17402: level = data & 7;
17403: } else {
17404: if(!pic[c].isr) {
17405: return;
17406: }
17407: level = pic[c].prio;
17408: while(!(pic[c].isr & (1 << level))) {
17409: level = (level + 1) & 7;
17410: }
17411: }
17412: if(data & 0x80) {
17413: pic[c].prio = (level + 1) & 7;
17414: }
17415: if(data & 0x20) {
17416: pic[c].isr &= ~(1 << level);
17417: }
17418: }
17419: }
17420: pic_update();
17421: }
17422:
17423: UINT8 pic_read(int c, UINT32 addr)
17424: {
17425: if(addr & 1) {
17426: return(pic[c].imr);
17427: } else {
17428: // polling mode is not supported...
17429: //if(pic[c].ocw3 & 4) {
17430: // return ???;
17431: //}
17432: if(pic[c].ocw3 & 1) {
17433: return(pic[c].isr);
17434: } else {
17435: return(pic[c].irr);
17436: }
17437: }
17438: }
17439:
17440: void pic_req(int c, int level, int signal)
17441: {
17442: if(signal) {
17443: pic[c].irr |= (1 << level);
17444: } else {
17445: pic[c].irr &= ~(1 << level);
17446: }
17447: pic_update();
17448: }
17449:
17450: int pic_ack()
17451: {
17452: // ack (INTA=L)
17453: pic[pic_req_chip].isr |= pic_req_bit;
17454: pic[pic_req_chip].irr &= ~pic_req_bit;
17455: if(pic_req_chip > 0) {
17456: // update isr and irr of master
17457: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
17458: pic[pic_req_chip - 1].isr |= slave;
17459: pic[pic_req_chip - 1].irr &= ~slave;
17460: }
17461: //if(pic[pic_req_chip].icw4 & 1) {
17462: // 8086 mode
17463: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
17464: //} else {
17465: // // 8080 mode
17466: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
17467: // if(pic[pic_req_chip].icw1 & 4) {
17468: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
17469: // } else {
17470: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
17471: // }
17472: // vector = 0xcd | (addr << 8);
17473: //}
17474: if(pic[pic_req_chip].icw4 & 2) {
17475: // auto eoi
17476: pic[pic_req_chip].isr &= ~pic_req_bit;
17477: }
17478: return(vector);
17479: }
17480:
17481: void pic_update()
17482: {
17483: for(int c = 0; c < 2; c++) {
17484: UINT8 irr = pic[c].irr;
17485: if(c + 1 < 2) {
17486: // this is master
17487: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
17488: // request from slave
17489: irr |= 1 << (pic[c + 1].icw3 & 7);
17490: }
17491: }
17492: irr &= (~pic[c].imr);
17493: if(!irr) {
17494: break;
17495: }
17496: if(!(pic[c].ocw3 & 0x20)) {
17497: irr |= pic[c].isr;
17498: }
17499: int level = pic[c].prio;
17500: UINT8 bit = 1 << level;
17501: while(!(irr & bit)) {
17502: level = (level + 1) & 7;
17503: bit = 1 << level;
17504: }
17505: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
17506: // check slave
17507: continue;
17508: }
17509: if(pic[c].isr & bit) {
17510: break;
17511: }
17512: // interrupt request
17513: pic_req_chip = c;
17514: pic_req_level = level;
17515: pic_req_bit = bit;
1.1.1.3 root 17516: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 17517: return;
17518: }
1.1.1.3 root 17519: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 17520: }
1.1 root 17521:
1.1.1.25 root 17522: // pio
17523:
17524: void pio_init()
17525: {
1.1.1.38 root 17526: // bool conv_mode = (GetConsoleCP() == 932);
17527:
1.1.1.26 root 17528: memset(pio, 0, sizeof(pio));
1.1.1.37 root 17529:
1.1.1.25 root 17530: for(int c = 0; c < 2; c++) {
1.1.1.37 root 17531: pio[c].stat = 0xdf;
1.1.1.25 root 17532: pio[c].ctrl = 0x0c;
1.1.1.38 root 17533: // pio[c].conv_mode = conv_mode;
1.1.1.25 root 17534: }
17535: }
17536:
1.1.1.37 root 17537: void pio_finish()
17538: {
17539: pio_release();
17540: }
17541:
17542: void pio_release()
17543: {
17544: for(int c = 0; c < 2; c++) {
17545: if(pio[c].fp != NULL) {
1.1.1.38 root 17546: if(pio[c].jis_mode) {
17547: fputc(0x1c, pio[c].fp);
17548: fputc(0x2e, pio[c].fp);
17549: }
1.1.1.37 root 17550: fclose(pio[c].fp);
17551: pio[c].fp = NULL;
17552: }
17553: }
17554: }
17555:
1.1.1.25 root 17556: void pio_write(int c, UINT32 addr, UINT8 data)
17557: {
17558: switch(addr & 3) {
17559: case 0:
17560: pio[c].data = data;
17561: break;
17562: case 2:
1.1.1.37 root 17563: if((pio[c].ctrl & 0x01) && !(data & 0x01)) {
17564: // strobe H -> L
17565: if(pio[c].data == 0x0d && (data & 0x02)) {
17566: // auto feed
17567: printer_out(c, 0x0d);
17568: printer_out(c, 0x0a);
17569: } else {
17570: printer_out(c, pio[c].data);
17571: }
17572: pio[c].stat &= ~0x40; // set ack
17573: }
1.1.1.25 root 17574: pio[c].ctrl = data;
17575: break;
17576: }
17577: }
17578:
17579: UINT8 pio_read(int c, UINT32 addr)
17580: {
17581: switch(addr & 3) {
17582: case 0:
1.1.1.37 root 17583: if(pio[c].ctrl & 0x20) {
17584: // input mode
17585: return(0xff);
17586: }
1.1.1.25 root 17587: return(pio[c].data);
17588: case 1:
1.1.1.37 root 17589: {
17590: UINT8 stat = pio[c].stat;
17591: pio[c].stat |= 0x40; // clear ack
17592: return(stat);
17593: }
1.1.1.25 root 17594: case 2:
17595: return(pio[c].ctrl);
17596: }
17597: return(0xff);
17598: }
17599:
1.1.1.37 root 17600: void printer_out(int c, UINT8 data)
17601: {
17602: SYSTEMTIME time;
1.1.1.38 root 17603: bool jis_mode = false;
1.1.1.37 root 17604:
17605: GetLocalTime(&time);
17606:
17607: if(pio[c].fp != NULL) {
17608: // if at least 1000ms passed from last written, close the current file
17609: FILETIME ftime1;
17610: FILETIME ftime2;
17611: SystemTimeToFileTime(&pio[c].time, &ftime1);
17612: SystemTimeToFileTime(&time, &ftime2);
17613: INT64 *time1 = (INT64 *)&ftime1;
17614: INT64 *time2 = (INT64 *)&ftime2;
17615: INT64 msec = (*time2 - *time1) / 10000;
17616:
17617: if(msec >= 1000) {
1.1.1.38 root 17618: if(pio[c].jis_mode) {
17619: fputc(0x1c, pio[c].fp);
17620: fputc(0x2e, pio[c].fp);
17621: jis_mode = true;
17622: }
1.1.1.37 root 17623: fclose(pio[c].fp);
17624: pio[c].fp = NULL;
17625: }
17626: }
17627: if(pio[c].fp == NULL) {
17628: // create a new file in the temp folder
17629: char file_name[MAX_PATH];
17630:
17631: 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);
17632: if(GetTempPath(MAX_PATH, pio[c].path)) {
17633: strcat(pio[c].path, file_name);
17634: } else {
17635: strcpy(pio[c].path, file_name);
17636: }
1.1.1.38 root 17637: pio[c].fp = fopen(pio[c].path, "w+b");
1.1.1.37 root 17638: }
17639: if(pio[c].fp != NULL) {
1.1.1.38 root 17640: if(jis_mode) {
17641: fputc(0x1c, pio[c].fp);
17642: fputc(0x26, pio[c].fp);
17643: }
1.1.1.37 root 17644: fputc(data, pio[c].fp);
1.1.1.38 root 17645:
17646: // reopen file if 1ch 26h 1ch 2eh (kanji-on kanji-off) are written at the top
17647: if(data == 0x2e && ftell(pio[c].fp) == 4) {
17648: UINT8 buffer[4];
17649: fseek(pio[c].fp, 0, SEEK_SET);
17650: fread(buffer, 4, 1, pio[c].fp);
17651: if(buffer[0] == 0x1c && buffer[1] == 0x26 && buffer[2] == 0x1c/* && buffer[3] == 0x2e*/) {
17652: fclose(pio[c].fp);
17653: pio[c].fp = fopen(pio[c].path, "w+b");
17654: }
17655: }
1.1.1.37 root 17656: pio[c].time = time;
17657: }
17658: }
17659:
1.1 root 17660: // pit
17661:
1.1.1.22 root 17662: #define PIT_FREQ 1193182ULL
1.1 root 17663: #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)
17664:
17665: void pit_init()
17666: {
1.1.1.8 root 17667: memset(pit, 0, sizeof(pit));
1.1 root 17668: for(int ch = 0; ch < 3; ch++) {
17669: pit[ch].count = 0x10000;
17670: pit[ch].ctrl_reg = 0x34;
17671: pit[ch].mode = 3;
17672: }
17673:
17674: // from bochs bios
17675: pit_write(3, 0x34);
17676: pit_write(0, 0x00);
17677: pit_write(0, 0x00);
17678: }
17679:
17680: void pit_write(int ch, UINT8 val)
17681: {
1.1.1.8 root 17682: #ifndef PIT_ALWAYS_RUNNING
1.1 root 17683: if(!pit_active) {
17684: pit_active = 1;
17685: pit_init();
17686: }
1.1.1.8 root 17687: #endif
1.1 root 17688: switch(ch) {
17689: case 0:
17690: case 1:
17691: case 2:
17692: // write count register
17693: if(!pit[ch].low_write && !pit[ch].high_write) {
17694: if(pit[ch].ctrl_reg & 0x10) {
17695: pit[ch].low_write = 1;
17696: }
17697: if(pit[ch].ctrl_reg & 0x20) {
17698: pit[ch].high_write = 1;
17699: }
17700: }
17701: if(pit[ch].low_write) {
17702: pit[ch].count_reg = val;
17703: pit[ch].low_write = 0;
17704: } else if(pit[ch].high_write) {
17705: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
17706: pit[ch].count_reg = val << 8;
17707: } else {
17708: pit[ch].count_reg |= val << 8;
17709: }
17710: pit[ch].high_write = 0;
17711: }
17712: // start count
1.1.1.8 root 17713: if(!pit[ch].low_write && !pit[ch].high_write) {
17714: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
17715: pit[ch].count = PIT_COUNT_VALUE(ch);
17716: pit[ch].prev_time = timeGetTime();
17717: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 17718: }
17719: }
17720: break;
17721: case 3: // ctrl reg
17722: if((val & 0xc0) == 0xc0) {
17723: // i8254 read-back command
17724: for(ch = 0; ch < 3; ch++) {
17725: if(!(val & 0x10) && !pit[ch].status_latched) {
17726: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
17727: pit[ch].status_latched = 1;
17728: }
17729: if(!(val & 0x20) && !pit[ch].count_latched) {
17730: pit_latch_count(ch);
17731: }
17732: }
17733: break;
17734: }
17735: ch = (val >> 6) & 3;
17736: if(val & 0x30) {
1.1.1.35 root 17737: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
1.1 root 17738: pit[ch].mode = modes[(val >> 1) & 7];
17739: pit[ch].count_latched = 0;
17740: pit[ch].low_read = pit[ch].high_read = 0;
17741: pit[ch].low_write = pit[ch].high_write = 0;
17742: pit[ch].ctrl_reg = val;
17743: // stop count
1.1.1.8 root 17744: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 17745: pit[ch].count_reg = 0;
17746: } else if(!pit[ch].count_latched) {
17747: pit_latch_count(ch);
17748: }
17749: break;
17750: }
17751: }
17752:
17753: UINT8 pit_read(int ch)
17754: {
1.1.1.8 root 17755: #ifndef PIT_ALWAYS_RUNNING
1.1 root 17756: if(!pit_active) {
17757: pit_active = 1;
17758: pit_init();
17759: }
1.1.1.8 root 17760: #endif
1.1 root 17761: switch(ch) {
17762: case 0:
17763: case 1:
17764: case 2:
17765: if(pit[ch].status_latched) {
17766: pit[ch].status_latched = 0;
17767: return(pit[ch].status);
17768: }
17769: // if not latched, through current count
17770: if(!pit[ch].count_latched) {
17771: if(!pit[ch].low_read && !pit[ch].high_read) {
17772: pit_latch_count(ch);
17773: }
17774: }
17775: // return latched count
17776: if(pit[ch].low_read) {
17777: pit[ch].low_read = 0;
17778: if(!pit[ch].high_read) {
17779: pit[ch].count_latched = 0;
17780: }
17781: return(pit[ch].latch & 0xff);
17782: } else if(pit[ch].high_read) {
17783: pit[ch].high_read = 0;
17784: pit[ch].count_latched = 0;
17785: return((pit[ch].latch >> 8) & 0xff);
17786: }
17787: }
17788: return(0xff);
17789: }
17790:
1.1.1.8 root 17791: int pit_run(int ch, UINT32 cur_time)
1.1 root 17792: {
1.1.1.8 root 17793: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 17794: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 17795: pit[ch].prev_time = pit[ch].expired_time;
17796: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
17797: if(cur_time >= pit[ch].expired_time) {
17798: pit[ch].prev_time = cur_time;
17799: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 17800: }
1.1.1.8 root 17801: return(1);
1.1 root 17802: }
1.1.1.8 root 17803: return(0);
1.1 root 17804: }
17805:
17806: void pit_latch_count(int ch)
17807: {
1.1.1.8 root 17808: if(pit[ch].expired_time != 0) {
1.1.1.26 root 17809: UINT32 cur_time = timeGetTime();
1.1.1.8 root 17810: pit_run(ch, cur_time);
17811: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 17812: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
17813:
17814: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
17815: // decrement counter in 1msec period
17816: if(pit[ch].next_latch == 0) {
17817: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
17818: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
17819: }
17820: if(pit[ch].latch > pit[ch].next_latch) {
17821: pit[ch].latch--;
17822: }
17823: } else {
17824: pit[ch].prev_latch = pit[ch].latch = latch;
17825: pit[ch].next_latch = 0;
17826: }
1.1.1.8 root 17827: } else {
17828: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 17829: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 17830: }
17831: pit[ch].count_latched = 1;
17832: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
17833: // lower byte
17834: pit[ch].low_read = 1;
17835: pit[ch].high_read = 0;
17836: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
17837: // upper byte
17838: pit[ch].low_read = 0;
17839: pit[ch].high_read = 1;
17840: } else {
17841: // lower -> upper
1.1.1.14 root 17842: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 17843: }
17844: }
17845:
1.1.1.8 root 17846: int pit_get_expired_time(int ch)
1.1 root 17847: {
1.1.1.22 root 17848: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
17849: UINT64 val = pit[ch].accum >> 10;
17850: pit[ch].accum -= val << 10;
17851: return((val != 0) ? val : 1);
1.1.1.8 root 17852: }
17853:
1.1.1.25 root 17854: // sio
17855:
17856: void sio_init()
17857: {
1.1.1.26 root 17858: memset(sio, 0, sizeof(sio));
17859: memset(sio_mt, 0, sizeof(sio_mt));
17860:
1.1.1.29 root 17861: for(int c = 0; c < 4; c++) {
1.1.1.25 root 17862: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
17863: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
17864:
17865: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
17866: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 17867: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
17868: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 17869: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
17870: sio[c].irq_identify = 0x01; // no pending irq
17871:
17872: InitializeCriticalSection(&sio_mt[c].csSendData);
17873: InitializeCriticalSection(&sio_mt[c].csRecvData);
17874: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
17875: InitializeCriticalSection(&sio_mt[c].csLineStat);
17876: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
17877: InitializeCriticalSection(&sio_mt[c].csModemStat);
17878:
1.1.1.26 root 17879: if(sio_port_number[c] != 0) {
1.1.1.25 root 17880: sio[c].channel = c;
17881: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
17882: }
17883: }
17884: }
17885:
17886: void sio_finish()
17887: {
1.1.1.29 root 17888: for(int c = 0; c < 4; c++) {
1.1.1.25 root 17889: if(sio_mt[c].hThread != NULL) {
17890: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
17891: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 17892: sio_mt[c].hThread = NULL;
1.1.1.25 root 17893: }
17894: DeleteCriticalSection(&sio_mt[c].csSendData);
17895: DeleteCriticalSection(&sio_mt[c].csRecvData);
17896: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
17897: DeleteCriticalSection(&sio_mt[c].csLineStat);
17898: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
17899: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 17900: }
17901: sio_release();
17902: }
17903:
17904: void sio_release()
17905: {
1.1.1.29 root 17906: for(int c = 0; c < 4; c++) {
1.1.1.28 root 17907: // sio_thread() may access the resources :-(
1.1.1.32 root 17908: bool running = (sio_mt[c].hThread != NULL);
17909:
17910: if(running) {
17911: EnterCriticalSection(&sio_mt[c].csSendData);
17912: }
17913: if(sio[c].send_buffer != NULL) {
17914: sio[c].send_buffer->release();
17915: delete sio[c].send_buffer;
17916: sio[c].send_buffer = NULL;
17917: }
17918: if(running) {
17919: LeaveCriticalSection(&sio_mt[c].csSendData);
17920: EnterCriticalSection(&sio_mt[c].csRecvData);
17921: }
17922: if(sio[c].recv_buffer != NULL) {
17923: sio[c].recv_buffer->release();
17924: delete sio[c].recv_buffer;
17925: sio[c].recv_buffer = NULL;
17926: }
17927: if(running) {
17928: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 17929: }
1.1.1.25 root 17930: }
17931: }
17932:
17933: void sio_write(int c, UINT32 addr, UINT8 data)
17934: {
17935: switch(addr & 7) {
17936: case 0:
17937: if(sio[c].selector & 0x80) {
17938: if(sio[c].divisor.b.l != data) {
17939: EnterCriticalSection(&sio_mt[c].csLineCtrl);
17940: sio[c].divisor.b.l = data;
17941: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
17942: }
17943: } else {
17944: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 17945: if(sio[c].send_buffer != NULL) {
17946: sio[c].send_buffer->write(data);
17947: }
1.1.1.25 root 17948: // transmitter holding/shift registers are not empty
17949: sio[c].line_stat_buf &= ~0x60;
17950: LeaveCriticalSection(&sio_mt[c].csSendData);
17951:
17952: if(sio[c].irq_enable & 0x02) {
17953: sio_update_irq(c);
17954: }
17955: }
17956: break;
17957: case 1:
17958: if(sio[c].selector & 0x80) {
17959: if(sio[c].divisor.b.h != data) {
17960: EnterCriticalSection(&sio_mt[c].csLineCtrl);
17961: sio[c].divisor.b.h = data;
17962: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
17963: }
17964: } else {
17965: if(sio[c].irq_enable != data) {
17966: sio[c].irq_enable = data;
17967: sio_update_irq(c);
17968: }
17969: }
17970: break;
17971: case 3:
17972: {
17973: UINT8 line_ctrl = data & 0x3f;
17974: bool set_brk = ((data & 0x40) != 0);
17975:
17976: if(sio[c].line_ctrl != line_ctrl) {
17977: EnterCriticalSection(&sio_mt[c].csLineCtrl);
17978: sio[c].line_ctrl = line_ctrl;
17979: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
17980: }
17981: if(sio[c].set_brk != set_brk) {
17982: EnterCriticalSection(&sio_mt[c].csModemCtrl);
17983: sio[c].set_brk = set_brk;
17984: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
17985: }
17986: }
17987: sio[c].selector = data;
17988: break;
17989: case 4:
17990: {
17991: bool set_dtr = ((data & 0x01) != 0);
17992: bool set_rts = ((data & 0x02) != 0);
17993:
17994: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 17995: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 17996: sio[c].set_dtr = set_dtr;
17997: sio[c].set_rts = set_rts;
1.1.1.26 root 17998: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
17999:
18000: bool state_changed = false;
18001:
18002: EnterCriticalSection(&sio_mt[c].csModemStat);
18003: if(set_dtr) {
18004: sio[c].modem_stat |= 0x20; // dsr on
18005: } else {
18006: sio[c].modem_stat &= ~0x20; // dsr off
18007: }
18008: if(set_rts) {
18009: sio[c].modem_stat |= 0x10; // cts on
18010: } else {
18011: sio[c].modem_stat &= ~0x10; // cts off
18012: }
18013: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
18014: if(!(sio[c].modem_stat & 0x02)) {
18015: if(sio[c].irq_enable & 0x08) {
18016: state_changed = true;
18017: }
18018: sio[c].modem_stat |= 0x02;
18019: }
18020: }
18021: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
18022: if(!(sio[c].modem_stat & 0x01)) {
18023: if(sio[c].irq_enable & 0x08) {
18024: state_changed = true;
18025: }
18026: sio[c].modem_stat |= 0x01;
18027: }
18028: }
18029: LeaveCriticalSection(&sio_mt[c].csModemStat);
18030:
18031: if(state_changed) {
18032: sio_update_irq(c);
18033: }
1.1.1.25 root 18034: }
18035: }
18036: sio[c].modem_ctrl = data;
18037: break;
18038: case 7:
18039: sio[c].scratch = data;
18040: break;
18041: }
18042: }
18043:
18044: UINT8 sio_read(int c, UINT32 addr)
18045: {
18046: switch(addr & 7) {
18047: case 0:
18048: if(sio[c].selector & 0x80) {
18049: return(sio[c].divisor.b.l);
18050: } else {
18051: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 18052: UINT8 data = 0;
18053: if(sio[c].recv_buffer != NULL) {
18054: data = sio[c].recv_buffer->read();
18055: }
1.1.1.25 root 18056: // data is not ready
18057: sio[c].line_stat_buf &= ~0x01;
18058: LeaveCriticalSection(&sio_mt[c].csRecvData);
18059:
18060: if(sio[c].irq_enable & 0x01) {
18061: sio_update_irq(c);
18062: }
18063: return(data);
18064: }
18065: case 1:
18066: if(sio[c].selector & 0x80) {
18067: return(sio[c].divisor.b.h);
18068: } else {
18069: return(sio[c].irq_enable);
18070: }
18071: case 2:
18072: return(sio[c].irq_identify);
18073: case 3:
18074: return(sio[c].selector);
18075: case 4:
18076: return(sio[c].modem_ctrl);
18077: case 5:
18078: {
18079: EnterCriticalSection(&sio_mt[c].csLineStat);
18080: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
18081: sio[c].line_stat_err = 0x00;
18082: LeaveCriticalSection(&sio_mt[c].csLineStat);
18083:
18084: bool state_changed = false;
18085:
18086: if((sio[c].line_stat_buf & 0x60) == 0x00) {
18087: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 18088: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 18089: // transmitter holding register will be empty first
18090: if(sio[c].irq_enable & 0x02) {
18091: state_changed = true;
18092: }
18093: sio[c].line_stat_buf |= 0x20;
18094: }
18095: LeaveCriticalSection(&sio_mt[c].csSendData);
18096: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
18097: // transmitter shift register will be empty later
18098: sio[c].line_stat_buf |= 0x40;
18099: }
18100: if(!(sio[c].line_stat_buf & 0x01)) {
18101: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 18102: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 18103: // data is ready
18104: if(sio[c].irq_enable & 0x01) {
18105: state_changed = true;
18106: }
18107: sio[c].line_stat_buf |= 0x01;
18108: }
18109: LeaveCriticalSection(&sio_mt[c].csRecvData);
18110: }
18111: if(state_changed) {
18112: sio_update_irq(c);
18113: }
18114: return(val);
18115: }
18116: case 6:
18117: {
18118: EnterCriticalSection(&sio_mt[c].csModemStat);
18119: UINT8 val = sio[c].modem_stat;
18120: sio[c].modem_stat &= 0xf0;
18121: sio[c].prev_modem_stat = sio[c].modem_stat;
18122: LeaveCriticalSection(&sio_mt[c].csModemStat);
18123:
18124: if(sio[c].modem_ctrl & 0x10) {
18125: // loop-back
18126: val &= 0x0f;
18127: val |= (sio[c].modem_ctrl & 0x0c) << 4;
18128: val |= (sio[c].modem_ctrl & 0x01) << 5;
18129: val |= (sio[c].modem_ctrl & 0x02) << 3;
18130: }
18131: return(val);
18132: }
18133: case 7:
18134: return(sio[c].scratch);
18135: }
18136: return(0xff);
18137: }
18138:
18139: void sio_update(int c)
18140: {
18141: if((sio[c].line_stat_buf & 0x60) == 0x00) {
18142: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 18143: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 18144: // transmitter holding/shift registers will be empty
18145: sio[c].line_stat_buf |= 0x60;
18146: }
18147: LeaveCriticalSection(&sio_mt[c].csSendData);
18148: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
18149: // transmitter shift register will be empty
18150: sio[c].line_stat_buf |= 0x40;
18151: }
18152: if(!(sio[c].line_stat_buf & 0x01)) {
18153: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 18154: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 18155: // data is ready
18156: sio[c].line_stat_buf |= 0x01;
18157: }
18158: LeaveCriticalSection(&sio_mt[c].csRecvData);
18159: }
18160: sio_update_irq(c);
18161: }
18162:
18163: void sio_update_irq(int c)
18164: {
18165: int level = -1;
18166:
18167: if(sio[c].irq_enable & 0x08) {
18168: EnterCriticalSection(&sio_mt[c].csModemStat);
18169: if((sio[c].modem_stat & 0x0f) != 0) {
18170: level = 0;
18171: }
18172: EnterCriticalSection(&sio_mt[c].csModemStat);
18173: }
18174: if(sio[c].irq_enable & 0x02) {
18175: if(sio[c].line_stat_buf & 0x20) {
18176: level = 1;
18177: }
18178: }
18179: if(sio[c].irq_enable & 0x01) {
18180: if(sio[c].line_stat_buf & 0x01) {
18181: level = 2;
18182: }
18183: }
18184: if(sio[c].irq_enable & 0x04) {
18185: EnterCriticalSection(&sio_mt[c].csLineStat);
18186: if(sio[c].line_stat_err != 0) {
18187: level = 3;
18188: }
18189: LeaveCriticalSection(&sio_mt[c].csLineStat);
18190: }
1.1.1.29 root 18191:
18192: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 18193: if(level != -1) {
18194: sio[c].irq_identify = level << 1;
1.1.1.29 root 18195: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 18196: } else {
18197: sio[c].irq_identify = 1;
1.1.1.29 root 18198: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 18199: }
18200: }
18201:
18202: DWORD WINAPI sio_thread(void *lpx)
18203: {
18204: volatile sio_t *p = (sio_t *)lpx;
18205: sio_mt_t *q = &sio_mt[p->channel];
18206:
18207: char name[] = "COM1";
1.1.1.26 root 18208: name[3] = '0' + sio_port_number[p->channel];
18209: HANDLE hComm = NULL;
18210: COMMPROP commProp;
18211: DCB dcb;
18212: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
18213: BYTE bytBuffer[SIO_BUFFER_SIZE];
18214:
18215: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
18216: if(GetCommProperties(hComm, &commProp)) {
18217: dwSettableBaud = commProp.dwSettableBaud;
18218: }
1.1.1.25 root 18219: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 18220: // EscapeCommFunction(hComm, SETRTS);
18221: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 18222:
18223: while(!m_halted) {
18224: // setup comm port
18225: bool comm_state_changed = false;
18226:
18227: EnterCriticalSection(&q->csLineCtrl);
18228: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
18229: p->prev_divisor = p->divisor.w;
18230: p->prev_line_ctrl = p->line_ctrl;
18231: comm_state_changed = true;
18232: }
18233: LeaveCriticalSection(&q->csLineCtrl);
18234:
18235: if(comm_state_changed) {
1.1.1.26 root 18236: if(GetCommState(hComm, &dcb)) {
18237: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
18238: DWORD baud = 115200 / p->prev_divisor;
18239: dcb.BaudRate = 9600; // default
18240:
18241: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
18242: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
18243: // 134.5bps is not supported ???
18244: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
18245: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
18246: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
18247: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
18248: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
18249: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
18250: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
18251: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
18252: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
18253: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
18254: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
18255: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
18256: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
18257:
18258: switch(p->prev_line_ctrl & 0x03) {
18259: case 0x00: dcb.ByteSize = 5; break;
18260: case 0x01: dcb.ByteSize = 6; break;
18261: case 0x02: dcb.ByteSize = 7; break;
18262: case 0x03: dcb.ByteSize = 8; break;
18263: }
18264: switch(p->prev_line_ctrl & 0x04) {
18265: case 0x00: dcb.StopBits = ONESTOPBIT; break;
18266: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
18267: }
18268: switch(p->prev_line_ctrl & 0x38) {
18269: case 0x08: dcb.Parity = ODDPARITY; break;
18270: case 0x18: dcb.Parity = EVENPARITY; break;
18271: case 0x28: dcb.Parity = MARKPARITY; break;
18272: case 0x38: dcb.Parity = SPACEPARITY; break;
18273: default: dcb.Parity = NOPARITY; break;
18274: }
18275: dcb.fBinary = TRUE;
18276: dcb.fParity = (dcb.Parity != NOPARITY);
18277: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
18278: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
18279: dcb.fDsrSensitivity = FALSE;//TRUE;
18280: dcb.fTXContinueOnXoff = TRUE;
18281: dcb.fOutX = dcb.fInX = FALSE;
18282: dcb.fErrorChar = FALSE;
18283: dcb.fNull = FALSE;
18284: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
18285: dcb.fAbortOnError = FALSE;
18286:
18287: SetCommState(hComm, &dcb);
1.1.1.25 root 18288: }
18289:
18290: // check again to apply all comm state changes
18291: Sleep(10);
18292: continue;
18293: }
18294:
18295: // set comm pins
18296: bool change_brk = false;
1.1.1.26 root 18297: // bool change_rts = false;
18298: // bool change_dtr = false;
1.1.1.25 root 18299:
18300: EnterCriticalSection(&q->csModemCtrl);
18301: if(p->prev_set_brk != p->set_brk) {
18302: p->prev_set_brk = p->set_brk;
18303: change_brk = true;
18304: }
1.1.1.26 root 18305: // if(p->prev_set_rts != p->set_rts) {
18306: // p->prev_set_rts = p->set_rts;
18307: // change_rts = true;
18308: // }
18309: // if(p->prev_set_dtr != p->set_dtr) {
18310: // p->prev_set_dtr = p->set_dtr;
18311: // change_dtr = true;
18312: // }
1.1.1.25 root 18313: LeaveCriticalSection(&q->csModemCtrl);
18314:
18315: if(change_brk) {
1.1.1.26 root 18316: static UINT32 clear_time = 0;
18317: if(p->prev_set_brk) {
18318: EscapeCommFunction(hComm, SETBREAK);
18319: clear_time = timeGetTime() + 200;
18320: } else {
18321: // keep break for at least 200msec
18322: UINT32 cur_time = timeGetTime();
18323: if(clear_time > cur_time) {
18324: Sleep(clear_time - cur_time);
18325: }
18326: EscapeCommFunction(hComm, CLRBREAK);
18327: }
1.1.1.25 root 18328: }
1.1.1.26 root 18329: // if(change_rts) {
18330: // if(p->prev_set_rts) {
18331: // EscapeCommFunction(hComm, SETRTS);
18332: // } else {
18333: // EscapeCommFunction(hComm, CLRRTS);
18334: // }
18335: // }
18336: // if(change_dtr) {
18337: // if(p->prev_set_dtr) {
18338: // EscapeCommFunction(hComm, SETDTR);
18339: // } else {
18340: // EscapeCommFunction(hComm, CLRDTR);
18341: // }
18342: // }
1.1.1.25 root 18343:
18344: // get comm pins
18345: DWORD dwModemStat = 0;
18346:
18347: if(GetCommModemStatus(hComm, &dwModemStat)) {
18348: EnterCriticalSection(&q->csModemStat);
18349: if(dwModemStat & MS_RLSD_ON) {
18350: p->modem_stat |= 0x80;
18351: } else {
18352: p->modem_stat &= ~0x80;
18353: }
18354: if(dwModemStat & MS_RING_ON) {
18355: p->modem_stat |= 0x40;
18356: } else {
18357: p->modem_stat &= ~0x40;
18358: }
1.1.1.26 root 18359: // if(dwModemStat & MS_DSR_ON) {
18360: // p->modem_stat |= 0x20;
18361: // } else {
18362: // p->modem_stat &= ~0x20;
18363: // }
18364: // if(dwModemStat & MS_CTS_ON) {
18365: // p->modem_stat |= 0x10;
18366: // } else {
18367: // p->modem_stat &= ~0x10;
18368: // }
1.1.1.25 root 18369: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
18370: p->modem_stat |= 0x08;
18371: }
18372: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
18373: p->modem_stat |= 0x04;
18374: }
1.1.1.26 root 18375: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
18376: // p->modem_stat |= 0x02;
18377: // }
18378: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
18379: // p->modem_stat |= 0x01;
18380: // }
1.1.1.25 root 18381: LeaveCriticalSection(&q->csModemStat);
18382: }
18383:
18384: // send data
18385: DWORD dwSend = 0;
18386:
18387: EnterCriticalSection(&q->csSendData);
1.1.1.32 root 18388: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 18389: bytBuffer[dwSend++] = p->send_buffer->read();
18390: }
18391: LeaveCriticalSection(&q->csSendData);
18392:
18393: if(dwSend != 0) {
18394: DWORD dwWritten = 0;
18395: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
18396: }
18397:
18398: // get line status and recv data
18399: DWORD dwLineStat = 0;
18400: COMSTAT comStat;
18401:
18402: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
18403: EnterCriticalSection(&q->csLineStat);
18404: if(dwLineStat & CE_BREAK) {
18405: p->line_stat_err |= 0x10;
18406: }
18407: if(dwLineStat & CE_FRAME) {
18408: p->line_stat_err |= 0x08;
18409: }
18410: if(dwLineStat & CE_RXPARITY) {
18411: p->line_stat_err |= 0x04;
18412: }
18413: if(dwLineStat & CE_OVERRUN) {
18414: p->line_stat_err |= 0x02;
18415: }
18416: LeaveCriticalSection(&q->csLineStat);
18417:
18418: if(comStat.cbInQue != 0) {
18419: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 18420: DWORD dwRecv = 0;
18421: if(p->recv_buffer != NULL) {
18422: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
18423: }
1.1.1.25 root 18424: LeaveCriticalSection(&q->csRecvData);
18425:
18426: if(dwRecv != 0) {
18427: DWORD dwRead = 0;
18428: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
18429: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 18430: if(p->recv_buffer != NULL) {
18431: for(int i = 0; i < dwRead; i++) {
18432: p->recv_buffer->write(bytBuffer[i]);
18433: }
1.1.1.25 root 18434: }
18435: LeaveCriticalSection(&q->csRecvData);
18436: }
18437: }
18438: }
18439: }
18440: Sleep(10);
18441: }
18442: CloseHandle(hComm);
18443: }
18444: return 0;
18445: }
18446:
1.1.1.8 root 18447: // cmos
18448:
18449: void cmos_init()
18450: {
18451: memset(cmos, 0, sizeof(cmos));
18452: cmos_addr = 0;
1.1 root 18453:
1.1.1.8 root 18454: // from DOSBox
18455: cmos_write(0x0a, 0x26);
18456: cmos_write(0x0b, 0x02);
18457: cmos_write(0x0d, 0x80);
1.1 root 18458: }
18459:
1.1.1.8 root 18460: void cmos_write(int addr, UINT8 val)
1.1 root 18461: {
1.1.1.8 root 18462: cmos[addr & 0x7f] = val;
18463: }
18464:
18465: #define CMOS_GET_TIME() { \
18466: UINT32 cur_sec = timeGetTime() / 1000 ; \
18467: if(prev_sec != cur_sec) { \
18468: GetLocalTime(&time); \
18469: prev_sec = cur_sec; \
18470: } \
1.1 root 18471: }
1.1.1.8 root 18472: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 18473:
1.1.1.8 root 18474: UINT8 cmos_read(int addr)
1.1 root 18475: {
1.1.1.8 root 18476: static SYSTEMTIME time;
18477: static UINT32 prev_sec = 0;
1.1 root 18478:
1.1.1.8 root 18479: switch(addr & 0x7f) {
18480: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
18481: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
18482: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
18483: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
18484: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
18485: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
18486: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
18487: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
18488: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
18489: case 0x15: return((MEMORY_END >> 10) & 0xff);
18490: case 0x16: return((MEMORY_END >> 18) & 0xff);
18491: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
18492: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
18493: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
18494: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
18495: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 18496: }
1.1.1.8 root 18497: return(cmos[addr & 0x7f]);
1.1 root 18498: }
18499:
1.1.1.7 root 18500: // kbd (a20)
18501:
18502: void kbd_init()
18503: {
1.1.1.8 root 18504: kbd_data = kbd_command = 0;
1.1.1.7 root 18505: kbd_status = 0x18;
18506: }
18507:
18508: UINT8 kbd_read_data()
18509: {
1.1.1.8 root 18510: kbd_status &= ~1;
1.1.1.7 root 18511: return(kbd_data);
18512: }
18513:
18514: void kbd_write_data(UINT8 val)
18515: {
18516: switch(kbd_command) {
18517: case 0xd1:
18518: i386_set_a20_line((val >> 1) & 1);
18519: break;
18520: }
18521: kbd_command = 0;
1.1.1.8 root 18522: kbd_status &= ~8;
1.1.1.7 root 18523: }
18524:
18525: UINT8 kbd_read_status()
18526: {
18527: return(kbd_status);
18528: }
18529:
18530: void kbd_write_command(UINT8 val)
18531: {
18532: switch(val) {
18533: case 0xd0:
18534: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 18535: kbd_status |= 1;
1.1.1.7 root 18536: break;
18537: case 0xdd:
18538: i386_set_a20_line(0);
18539: break;
18540: case 0xdf:
18541: i386_set_a20_line(1);
18542: break;
1.1.1.26 root 18543: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
18544: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 18545: if(!(val & 1)) {
1.1.1.8 root 18546: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 18547: // reset pic
18548: pic_init();
18549: pic[0].irr = pic[1].irr = 0x00;
18550: pic[0].imr = pic[1].imr = 0xff;
18551: }
18552: CPU_RESET_CALL(CPU_MODEL);
1.1.1.40 root 18553: UINT16 address = *(UINT16 *)(mem + 0x467);
18554: UINT16 selector = *(UINT16 *)(mem + 0x469);
18555: i386_jmp_far(selector, address);
1.1.1.7 root 18556: }
18557: i386_set_a20_line((val >> 1) & 1);
18558: break;
18559: }
18560: kbd_command = val;
1.1.1.8 root 18561: kbd_status |= 8;
1.1.1.7 root 18562: }
18563:
1.1.1.9 root 18564: // vga
18565:
18566: UINT8 vga_read_status()
18567: {
18568: // 60hz
18569: static const int period[3] = {16, 17, 17};
18570: static int index = 0;
18571: UINT32 time = timeGetTime() % period[index];
18572:
18573: index = (index + 1) % 3;
1.1.1.14 root 18574: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 18575: }
18576:
1.1 root 18577: // i/o bus
18578:
1.1.1.29 root 18579: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
18580: //#define SW1US_PATCH
18581:
1.1.1.25 root 18582: UINT8 read_io_byte(offs_t addr)
1.1.1.33 root 18583: #ifdef USE_DEBUGGER
1.1.1.25 root 18584: {
1.1.1.33 root 18585: if(now_debugging) {
18586: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
18587: if(in_break_point.table[i].status == 1) {
18588: if(addr == in_break_point.table[i].addr) {
18589: in_break_point.hit = i + 1;
18590: now_suspended = true;
18591: break;
18592: }
18593: }
18594: }
1.1.1.25 root 18595: }
1.1.1.33 root 18596: return(debugger_read_io_byte(addr));
1.1.1.25 root 18597: }
1.1.1.33 root 18598: UINT8 debugger_read_io_byte(offs_t addr)
1.1.1.25 root 18599: #endif
1.1 root 18600: {
1.1.1.33 root 18601: UINT8 val = 0xff;
18602:
1.1 root 18603: switch(addr) {
1.1.1.29 root 18604: #ifdef SW1US_PATCH
18605: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
18606: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
1.1.1.33 root 18607: val = sio_read(0, addr - 1);
18608: break;
1.1.1.29 root 18609: #else
1.1.1.25 root 18610: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
18611: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1.1.1.33 root 18612: val = dma_read(0, addr);
18613: break;
1.1.1.29 root 18614: #endif
1.1.1.25 root 18615: case 0x20: case 0x21:
1.1.1.33 root 18616: val = pic_read(0, addr);
18617: break;
1.1.1.25 root 18618: case 0x40: case 0x41: case 0x42: case 0x43:
1.1.1.33 root 18619: val = pit_read(addr & 0x03);
18620: break;
1.1.1.7 root 18621: case 0x60:
1.1.1.33 root 18622: val = kbd_read_data();
18623: break;
1.1.1.9 root 18624: case 0x61:
1.1.1.33 root 18625: val = system_port;
18626: break;
1.1.1.7 root 18627: case 0x64:
1.1.1.33 root 18628: val = kbd_read_status();
18629: break;
1.1 root 18630: case 0x71:
1.1.1.33 root 18631: val = cmos_read(cmos_addr);
18632: break;
1.1.1.25 root 18633: case 0x81:
1.1.1.33 root 18634: val = dma_page_read(0, 2);
18635: break;
1.1.1.25 root 18636: case 0x82:
1.1.1.33 root 18637: val = dma_page_read(0, 3);
18638: break;
1.1.1.25 root 18639: case 0x83:
1.1.1.33 root 18640: val = dma_page_read(0, 1);
18641: break;
1.1.1.25 root 18642: case 0x87:
1.1.1.33 root 18643: val = dma_page_read(0, 0);
18644: break;
1.1.1.25 root 18645: case 0x89:
1.1.1.33 root 18646: val = dma_page_read(1, 2);
18647: break;
1.1.1.25 root 18648: case 0x8a:
1.1.1.33 root 18649: val = dma_page_read(1, 3);
18650: break;
1.1.1.25 root 18651: case 0x8b:
1.1.1.33 root 18652: val = dma_page_read(1, 1);
18653: break;
1.1.1.25 root 18654: case 0x8f:
1.1.1.33 root 18655: val = dma_page_read(1, 0);
18656: break;
1.1 root 18657: case 0x92:
1.1.1.33 root 18658: val = (m_a20_mask >> 19) & 2;
18659: break;
1.1.1.25 root 18660: case 0xa0: case 0xa1:
1.1.1.33 root 18661: val = pic_read(1, addr);
18662: break;
1.1.1.25 root 18663: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
18664: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.33 root 18665: val = dma_read(1, (addr - 0xc0) >> 1);
18666: break;
1.1.1.37 root 18667: case 0x278: case 0x279: case 0x27a:
18668: val = pio_read(1, addr);
18669: break;
1.1.1.29 root 18670: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
1.1.1.33 root 18671: val = sio_read(3, addr);
18672: break;
1.1.1.25 root 18673: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
1.1.1.33 root 18674: val = sio_read(1, addr);
18675: break;
1.1.1.25 root 18676: case 0x378: case 0x379: case 0x37a:
1.1.1.33 root 18677: val = pio_read(0, addr);
18678: break;
1.1.1.25 root 18679: case 0x3ba: case 0x3da:
1.1.1.33 root 18680: val = vga_read_status();
18681: break;
1.1.1.37 root 18682: case 0x3bc: case 0x3bd: case 0x3be:
18683: val = pio_read(2, addr);
18684: break;
1.1.1.29 root 18685: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
1.1.1.33 root 18686: val = sio_read(2, addr);
18687: break;
1.1.1.25 root 18688: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
1.1.1.33 root 18689: val = sio_read(0, addr);
18690: break;
1.1 root 18691: default:
1.1.1.33 root 18692: // fatalerror("unknown inb %4x\n", addr);
1.1 root 18693: break;
18694: }
1.1.1.33 root 18695: #ifdef ENABLE_DEBUG_IOPORT
18696: if(fp_debug_log != NULL) {
18697: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
18698: }
18699: #endif
18700: return(val);
1.1 root 18701: }
18702:
18703: UINT16 read_io_word(offs_t addr)
18704: {
18705: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
18706: }
18707:
1.1.1.33 root 18708: #ifdef USE_DEBUGGER
18709: UINT16 debugger_read_io_word(offs_t addr)
18710: {
18711: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
18712: }
18713: #endif
18714:
1.1 root 18715: UINT32 read_io_dword(offs_t addr)
18716: {
18717: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
18718: }
18719:
1.1.1.33 root 18720: #ifdef USE_DEBUGGER
18721: UINT32 debugger_read_io_dword(offs_t addr)
18722: {
18723: 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));
18724: }
18725: #endif
18726:
1.1 root 18727: void write_io_byte(offs_t addr, UINT8 val)
1.1.1.33 root 18728: #ifdef USE_DEBUGGER
18729: {
18730: if(now_debugging) {
18731: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
18732: if(out_break_point.table[i].status == 1) {
18733: if(addr == out_break_point.table[i].addr) {
18734: out_break_point.hit = i + 1;
18735: now_suspended = true;
18736: break;
18737: }
18738: }
18739: }
18740: }
18741: debugger_write_io_byte(addr, val);
18742: }
18743: void debugger_write_io_byte(offs_t addr, UINT8 val)
18744: #endif
1.1 root 18745: {
1.1.1.25 root 18746: #ifdef ENABLE_DEBUG_IOPORT
1.1.1.33 root 18747: if(fp_debug_log != NULL) {
1.1.1.43! root 18748: #ifdef USE_SERVICE_THREAD
! 18749: if(addr != 0xf7)
! 18750: #endif
1.1.1.33 root 18751: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
1.1.1.25 root 18752: }
18753: #endif
1.1 root 18754: switch(addr) {
1.1.1.29 root 18755: #ifdef SW1US_PATCH
18756: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
18757: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
18758: sio_write(0, addr - 1, val);
18759: break;
18760: #else
1.1.1.25 root 18761: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
18762: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
18763: dma_write(0, addr, val);
18764: break;
1.1.1.29 root 18765: #endif
1.1.1.25 root 18766: case 0x20: case 0x21:
1.1 root 18767: pic_write(0, addr, val);
18768: break;
1.1.1.25 root 18769: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 18770: pit_write(addr & 0x03, val);
18771: break;
1.1.1.7 root 18772: case 0x60:
18773: kbd_write_data(val);
18774: break;
1.1.1.9 root 18775: case 0x61:
18776: if((system_port & 3) != 3 && (val & 3) == 3) {
18777: // beep on
18778: // MessageBeep(-1);
18779: } else if((system_port & 3) == 3 && (val & 3) != 3) {
18780: // beep off
18781: }
18782: system_port = val;
18783: break;
1.1 root 18784: case 0x64:
1.1.1.7 root 18785: kbd_write_command(val);
1.1 root 18786: break;
18787: case 0x70:
18788: cmos_addr = val;
18789: break;
18790: case 0x71:
1.1.1.8 root 18791: cmos_write(cmos_addr, val);
1.1 root 18792: break;
1.1.1.25 root 18793: case 0x81:
18794: dma_page_write(0, 2, val);
18795: case 0x82:
18796: dma_page_write(0, 3, val);
18797: case 0x83:
18798: dma_page_write(0, 1, val);
18799: case 0x87:
18800: dma_page_write(0, 0, val);
18801: case 0x89:
18802: dma_page_write(1, 2, val);
18803: case 0x8a:
18804: dma_page_write(1, 3, val);
18805: case 0x8b:
18806: dma_page_write(1, 1, val);
18807: case 0x8f:
18808: dma_page_write(1, 0, val);
1.1 root 18809: case 0x92:
1.1.1.7 root 18810: i386_set_a20_line((val >> 1) & 1);
1.1 root 18811: break;
1.1.1.25 root 18812: case 0xa0: case 0xa1:
1.1 root 18813: pic_write(1, addr, val);
18814: break;
1.1.1.25 root 18815: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
18816: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 18817: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 18818: break;
1.1.1.35 root 18819: #ifdef USE_SERVICE_THREAD
18820: case 0xf7:
18821: // dummy i/o for BIOS/DOS service
1.1.1.36 root 18822: if(in_service && cursor_moved) {
18823: // update cursor position before service is done
18824: pcbios_update_cursor_position();
18825: cursor_moved = false;
18826: }
1.1.1.35 root 18827: finish_service_loop();
18828: break;
18829: #endif
1.1.1.37 root 18830: case 0x278: case 0x279: case 0x27a:
18831: pio_write(1, addr, val);
18832: break;
1.1.1.29 root 18833: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
18834: sio_write(3, addr, val);
18835: break;
1.1.1.25 root 18836: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
18837: sio_write(1, addr, val);
18838: break;
18839: case 0x378: case 0x379: case 0x37a:
18840: pio_write(0, addr, val);
18841: break;
1.1.1.37 root 18842: case 0x3bc: case 0x3bd: case 0x3be:
18843: pio_write(2, addr, val);
18844: break;
1.1.1.29 root 18845: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
18846: sio_write(2, addr, val);
18847: break;
1.1.1.25 root 18848: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
18849: sio_write(0, addr, val);
18850: break;
1.1 root 18851: default:
1.1.1.33 root 18852: // fatalerror("unknown outb %4x,%2x\n", addr, val);
1.1 root 18853: break;
18854: }
18855: }
18856:
18857: void write_io_word(offs_t addr, UINT16 val)
18858: {
18859: write_io_byte(addr + 0, (val >> 0) & 0xff);
18860: write_io_byte(addr + 1, (val >> 8) & 0xff);
18861: }
18862:
1.1.1.33 root 18863: #ifdef USE_DEBUGGER
18864: void debugger_write_io_word(offs_t addr, UINT16 val)
18865: {
18866: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
18867: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
18868: }
18869: #endif
18870:
1.1 root 18871: void write_io_dword(offs_t addr, UINT32 val)
18872: {
18873: write_io_byte(addr + 0, (val >> 0) & 0xff);
18874: write_io_byte(addr + 1, (val >> 8) & 0xff);
18875: write_io_byte(addr + 2, (val >> 16) & 0xff);
18876: write_io_byte(addr + 3, (val >> 24) & 0xff);
18877: }
1.1.1.33 root 18878:
18879: #ifdef USE_DEBUGGER
18880: void debugger_write_io_dword(offs_t addr, UINT32 val)
18881: {
18882: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
18883: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
18884: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
18885: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
18886: }
18887: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.